mirror of
https://github.com/jmagar/unraid-mcp.git
synced 2026-03-01 16:04:24 -08:00
Comprehensive fixes across Python code, shell scripts, and documentation addressing all remaining MEDIUM and LOW priority review comments. Python Code Fixes (27 fixes): - tools/info.py: Simplified dispatch with lookup tables, defensive guards, CPU fallback formatting, !s conversion flags, module-level sync assertion - tools/docker.py: Case-insensitive container ID regex, keyword-only confirm, module-level ALL_ACTIONS constant - tools/virtualization.py: Normalized single-VM dict responses, unified list/details queries - core/client.py: Fixed HTTP client singleton race condition, compound key substring matching for sensitive data redaction - subscriptions/: Extracted SSL context creation to shared helper in utils.py, replaced deprecated ssl._create_unverified_context API - tools/array.py: Renamed parity_history to parity_status, hoisted ALL_ACTIONS - tools/storage.py: Fixed dict(None) risks, temperature 0 falsiness bug - tools/notifications.py, keys.py, rclone.py: Fixed dict(None) TypeError risks - tests/: Fixed generator type annotations, added coverage for compound keys Shell Script Fixes (13 fixes): - dashboard.sh: Dynamic server discovery, conditional debug output, null-safe jq, notification count guard order, removed unused variables - unraid-query.sh: Proper JSON escaping via jq, --ignore-errors and --insecure CLI flags, TLS verification now on by default - validate-marketplace.sh: Removed unused YELLOW variable, defensive jq, simplified repository URL output Documentation Fixes (24+ fixes): - Version consistency: Updated all references to v0.2.0 across pyproject.toml, plugin.json, marketplace.json, MARKETPLACE.md, __init__.py, README files - Tool count updates: Changed all "26 tools" references to "10 tools, 90 actions" - Markdown lint: Fixed MD022, MD031, MD047 issues across multiple files - Research docs: Fixed auth headers, removed web artifacts, corrected stale info - Skills docs: Fixed query examples, endpoint counts, env var references All 227 tests pass, ruff and ty checks clean.
92 lines
3.4 KiB
Python
92 lines
3.4 KiB
Python
"""MCP resources that expose subscription data.
|
|
|
|
This module defines MCP resources that bridge between the subscription manager
|
|
and the MCP protocol, providing fallback queries when subscription data is unavailable.
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
|
|
from fastmcp import FastMCP
|
|
|
|
from ..config.logging import logger
|
|
from .manager import subscription_manager
|
|
|
|
|
|
# Global flag to track subscription startup
|
|
_subscriptions_started = False
|
|
|
|
|
|
async def ensure_subscriptions_started() -> None:
|
|
"""Ensure subscriptions are started, called from async context."""
|
|
global _subscriptions_started
|
|
|
|
if _subscriptions_started:
|
|
return
|
|
|
|
logger.info("[STARTUP] First async operation detected, starting subscriptions...")
|
|
try:
|
|
await autostart_subscriptions()
|
|
_subscriptions_started = True
|
|
logger.info("[STARTUP] Subscriptions started successfully")
|
|
except Exception as e:
|
|
logger.error(f"[STARTUP] Failed to start subscriptions: {e}", exc_info=True)
|
|
|
|
|
|
async def autostart_subscriptions() -> None:
|
|
"""Auto-start all subscriptions marked for auto-start in SubscriptionManager."""
|
|
logger.info("[AUTOSTART] Initiating subscription auto-start process...")
|
|
|
|
try:
|
|
# Use the new SubscriptionManager auto-start method
|
|
await subscription_manager.auto_start_all_subscriptions()
|
|
logger.info("[AUTOSTART] Auto-start process completed successfully")
|
|
except Exception as e:
|
|
logger.error(f"[AUTOSTART] Failed during auto-start process: {e}", exc_info=True)
|
|
|
|
# Optional log file subscription
|
|
log_path = os.getenv("UNRAID_AUTOSTART_LOG_PATH")
|
|
if log_path is None:
|
|
# Default to syslog if available
|
|
default_path = "/var/log/syslog"
|
|
if Path(default_path).exists():
|
|
log_path = default_path
|
|
logger.info(f"[AUTOSTART] Using default log path: {default_path}")
|
|
|
|
if log_path:
|
|
try:
|
|
logger.info(f"[AUTOSTART] Starting log file subscription for: {log_path}")
|
|
config = subscription_manager.subscription_configs.get("logFileSubscription")
|
|
if config:
|
|
await subscription_manager.start_subscription("logFileSubscription", str(config["query"]), {"path": log_path})
|
|
logger.info(f"[AUTOSTART] Log file subscription started for: {log_path}")
|
|
else:
|
|
logger.error("[AUTOSTART] logFileSubscription config not found")
|
|
except Exception as e:
|
|
logger.error(f"[AUTOSTART] Failed to start log file subscription: {e}", exc_info=True)
|
|
else:
|
|
logger.info("[AUTOSTART] No log file path configured for auto-start")
|
|
|
|
|
|
def register_subscription_resources(mcp: FastMCP) -> None:
|
|
"""Register all subscription resources with the FastMCP instance.
|
|
|
|
Args:
|
|
mcp: FastMCP instance to register resources with
|
|
"""
|
|
|
|
@mcp.resource("unraid://logs/stream")
|
|
async def logs_stream_resource() -> str:
|
|
"""Real-time log stream data from subscription."""
|
|
await ensure_subscriptions_started()
|
|
data = subscription_manager.get_resource_data("logFileSubscription")
|
|
if data:
|
|
return json.dumps(data, indent=2)
|
|
return json.dumps({
|
|
"status": "No subscription data yet",
|
|
"message": "Subscriptions auto-start on server boot. If this persists, check server logs for WebSocket/auth issues."
|
|
})
|
|
|
|
logger.info("Subscription resources registered successfully")
|