mirror of
https://github.com/jmagar/unraid-mcp.git
synced 2026-03-23 12:39:24 -07:00
feat(elicitation): add setup action to unraid_health
This commit is contained in:
@@ -194,3 +194,36 @@ class TestSafeDisplayUrl:
|
|||||||
# raises ValueError: Invalid IPv6 URL — this triggers the except branch.
|
# raises ValueError: Invalid IPv6 URL — this triggers the except branch.
|
||||||
result = safe_display_url("https://[invalid")
|
result = safe_display_url("https://[invalid")
|
||||||
assert result == "<unparseable>"
|
assert result == "<unparseable>"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_health_setup_action_calls_elicitation() -> None:
|
||||||
|
"""setup action triggers elicit_and_configure and returns success message."""
|
||||||
|
from unittest.mock import AsyncMock, MagicMock
|
||||||
|
|
||||||
|
tool_fn = _make_tool()
|
||||||
|
|
||||||
|
with patch(
|
||||||
|
"unraid_mcp.tools.health.elicit_and_configure", new=AsyncMock(return_value=True)
|
||||||
|
) as mock_elicit:
|
||||||
|
result = await tool_fn(action="setup", ctx=MagicMock())
|
||||||
|
|
||||||
|
assert mock_elicit.called
|
||||||
|
assert "configured" in result.lower() or "success" in result.lower()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_health_setup_action_returns_declined_message() -> None:
|
||||||
|
"""setup action with declined elicitation returns appropriate message."""
|
||||||
|
from unittest.mock import AsyncMock, MagicMock
|
||||||
|
|
||||||
|
tool_fn = _make_tool()
|
||||||
|
|
||||||
|
with patch("unraid_mcp.tools.health.elicit_and_configure", new=AsyncMock(return_value=False)):
|
||||||
|
result = await tool_fn(action="setup", ctx=MagicMock())
|
||||||
|
|
||||||
|
assert (
|
||||||
|
"not configured" in result.lower()
|
||||||
|
or "declined" in result.lower()
|
||||||
|
or "cancel" in result.lower()
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
"""Health monitoring and diagnostics.
|
"""Health monitoring and diagnostics.
|
||||||
|
|
||||||
Provides the `unraid_health` tool with 3 actions for system health checks,
|
Provides the `unraid_health` tool with 4 actions for system health checks,
|
||||||
connection testing, and subscription diagnostics.
|
connection testing, subscription diagnostics, and credential setup.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
import time
|
import time
|
||||||
from typing import Any, Literal, get_args
|
from typing import Any, Literal, get_args
|
||||||
|
|
||||||
from fastmcp import FastMCP
|
from fastmcp import Context, FastMCP
|
||||||
|
|
||||||
from ..config.logging import logger
|
from ..config.logging import logger
|
||||||
from ..config.settings import (
|
from ..config.settings import (
|
||||||
@@ -20,13 +20,14 @@ from ..config.settings import (
|
|||||||
)
|
)
|
||||||
from ..core.client import make_graphql_request
|
from ..core.client import make_graphql_request
|
||||||
from ..core.exceptions import ToolError, tool_error_handler
|
from ..core.exceptions import ToolError, tool_error_handler
|
||||||
|
from ..core.setup import elicit_and_configure
|
||||||
from ..core.utils import safe_display_url
|
from ..core.utils import safe_display_url
|
||||||
from ..subscriptions.utils import _analyze_subscription_status
|
from ..subscriptions.utils import _analyze_subscription_status
|
||||||
|
|
||||||
|
|
||||||
ALL_ACTIONS = {"check", "test_connection", "diagnose"}
|
ALL_ACTIONS = {"check", "test_connection", "diagnose", "setup"}
|
||||||
|
|
||||||
HEALTH_ACTIONS = Literal["check", "test_connection", "diagnose"]
|
HEALTH_ACTIONS = Literal["check", "test_connection", "diagnose", "setup"]
|
||||||
|
|
||||||
if set(get_args(HEALTH_ACTIONS)) != ALL_ACTIONS:
|
if set(get_args(HEALTH_ACTIONS)) != ALL_ACTIONS:
|
||||||
_missing = ALL_ACTIONS - set(get_args(HEALTH_ACTIONS))
|
_missing = ALL_ACTIONS - set(get_args(HEALTH_ACTIONS))
|
||||||
@@ -57,10 +58,12 @@ def register_health_tool(mcp: FastMCP) -> None:
|
|||||||
@mcp.tool()
|
@mcp.tool()
|
||||||
async def unraid_health(
|
async def unraid_health(
|
||||||
action: HEALTH_ACTIONS,
|
action: HEALTH_ACTIONS,
|
||||||
) -> dict[str, Any]:
|
ctx: Context | None = None,
|
||||||
|
) -> dict[str, Any] | str:
|
||||||
"""Monitor Unraid MCP server and system health.
|
"""Monitor Unraid MCP server and system health.
|
||||||
|
|
||||||
Actions:
|
Actions:
|
||||||
|
setup - Configure Unraid credentials via interactive elicitation
|
||||||
check - Comprehensive health check (API latency, array, notifications, Docker)
|
check - Comprehensive health check (API latency, array, notifications, Docker)
|
||||||
test_connection - Quick connectivity test (just checks { online })
|
test_connection - Quick connectivity test (just checks { online })
|
||||||
diagnose - Subscription system diagnostics
|
diagnose - Subscription system diagnostics
|
||||||
@@ -68,6 +71,17 @@ def register_health_tool(mcp: FastMCP) -> None:
|
|||||||
if action not in ALL_ACTIONS:
|
if action not in ALL_ACTIONS:
|
||||||
raise ToolError(f"Invalid action '{action}'. Must be one of: {sorted(ALL_ACTIONS)}")
|
raise ToolError(f"Invalid action '{action}'. Must be one of: {sorted(ALL_ACTIONS)}")
|
||||||
|
|
||||||
|
if action == "setup":
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if configured:
|
||||||
|
return (
|
||||||
|
"✅ Credentials configured successfully. You can now use all Unraid MCP tools."
|
||||||
|
)
|
||||||
|
return (
|
||||||
|
"⚠️ Credentials not configured. "
|
||||||
|
"Run `unraid_health action=setup` again to provide credentials."
|
||||||
|
)
|
||||||
|
|
||||||
with tool_error_handler("health", action, logger):
|
with tool_error_handler("health", action, logger):
|
||||||
logger.info(f"Executing unraid_health action={action}")
|
logger.info(f"Executing unraid_health action={action}")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user