fix: even more changes to accommodate older GraphQL schema

This commit is contained in:
2026-02-28 16:45:19 +01:00
parent f89ed7275b
commit 88983c6736
18 changed files with 20 additions and 218 deletions

View File

@@ -2,7 +2,6 @@
10 consolidated tools with ~90 actions total:
unraid_info - System information queries (19 actions)
unraid_array - Array operations and power management (12 actions)
unraid_storage - Storage, disks, and logs (6 actions)
unraid_docker - Docker container management (15 actions)
unraid_vm - Virtual machine management (9 actions)

View File

@@ -1,104 +0,0 @@
"""Array parity check operations.
Provides the `unraid_array` tool with 5 actions for parity check management.
"""
from typing import Any, Literal
from fastmcp import FastMCP
from ..config.logging import logger
from ..core.client import make_graphql_request
from ..core.exceptions import ToolError
QUERIES: dict[str, str] = {
"parity_status": """
query GetParityStatus {
array { parityCheckStatus { progress speed errors } }
}
""",
}
MUTATIONS: dict[str, str] = {
"parity_start": """
mutation StartParityCheck($correct: Boolean) {
parityCheck { start(correct: $correct) }
}
""",
"parity_pause": """
mutation PauseParityCheck {
parityCheck { pause }
}
""",
"parity_resume": """
mutation ResumeParityCheck {
parityCheck { resume }
}
""",
"parity_cancel": """
mutation CancelParityCheck {
parityCheck { cancel }
}
""",
}
ALL_ACTIONS = set(QUERIES) | set(MUTATIONS)
ARRAY_ACTIONS = Literal[
"parity_start",
"parity_pause",
"parity_resume",
"parity_cancel",
"parity_status",
]
def register_array_tool(mcp: FastMCP) -> None:
"""Register the unraid_array tool with the FastMCP instance."""
@mcp.tool()
async def unraid_array(
action: ARRAY_ACTIONS,
correct: bool | None = None,
) -> dict[str, Any]:
"""Manage Unraid array parity checks.
Actions:
parity_start - Start parity check (optional correct=True to fix errors)
parity_pause - Pause running parity check
parity_resume - Resume paused parity check
parity_cancel - Cancel running parity check
parity_status - Get current parity check status
"""
if action not in ALL_ACTIONS:
raise ToolError(f"Invalid action '{action}'. Must be one of: {sorted(ALL_ACTIONS)}")
try:
logger.info(f"Executing unraid_array action={action}")
if action in QUERIES:
data = await make_graphql_request(QUERIES[action])
return {"success": True, "action": action, "data": data}
query = MUTATIONS[action]
variables: dict[str, Any] | None = None
if action == "parity_start" and correct is not None:
variables = {"correct": correct}
data = await make_graphql_request(query, variables)
return {
"success": True,
"action": action,
"data": data,
}
except ToolError:
raise
except Exception as e:
logger.error(f"Error in unraid_array action={action}: {e}", exc_info=True)
raise ToolError(f"Failed to execute array/{action}: {e!s}") from e
logger.info("Array tool registered successfully")

View File

@@ -103,7 +103,6 @@ async def _comprehensive_check() -> dict[str, Any]:
query ComprehensiveHealthCheck {
info {
machineId time
versions { unraid }
os { uptime }
}
array { state }

View File

@@ -63,11 +63,6 @@ QUERIES: dict[str, str] = {
}
}
""",
"connect": """
query GetConnectSettings {
connect { status sandbox flashGuid }
}
""",
"variables": """
query GetSelectiveUnraidVariables {
vars {
@@ -85,12 +80,12 @@ QUERIES: dict[str, str] = {
""",
"metrics": """
query GetMetrics {
metrics { cpu { used } memory { used total } }
metrics { cpu { percentTotal cpus { percentTotal } } memory { used total } }
}
""",
"services": """
query GetServices {
services { name state }
services { name online uptime }
}
""",
"display": """
@@ -159,7 +154,6 @@ INFO_ACTIONS = Literal[
"array",
"network",
"registration",
"connect",
"variables",
"metrics",
"services",
@@ -327,7 +321,6 @@ def register_info_tool(mcp: FastMCP) -> None:
array - Array state, capacity, disk health
network - Access URLs, interfaces
registration - License type, state, expiration
connect - Unraid Connect settings
variables - System variables and configuration
metrics - CPU and memory utilization
services - Running services
@@ -359,7 +352,6 @@ def register_info_tool(mcp: FastMCP) -> None:
dict_actions: dict[str, str] = {
"network": "network",
"registration": "registration",
"connect": "connect",
"variables": "vars",
"metrics": "metrics",
"config": "config",

View File

@@ -16,12 +16,12 @@ from ..core.exceptions import ToolError
QUERIES: dict[str, str] = {
"list": """
query ListApiKeys {
apiKeys { id name roles permissions createdAt lastUsed }
apiKeys { id name roles permissions { resource actions } createdAt lastUsed }
}
""",
"get": """
query GetApiKey($id: PrefixedID!) {
apiKey(id: $id) { id name roles permissions createdAt lastUsed }
apiKey(id: $id) { id name roles permissions { resource actions } createdAt lastUsed }
}
""",
}

View File

@@ -1,7 +1,6 @@
"""Storage and disk management.
Provides the `unraid_storage` tool with 6 actions for shares, physical disks,
unassigned devices, log files, and log content retrieval.
Provides the `unraid_storage` tool with 6 actions for shares, physical disks, log files, and log content retrieval.
"""
from typing import Any, Literal
@@ -37,11 +36,6 @@ QUERIES: dict[str, str] = {
}
}
""",
"unassigned": """
query GetUnassignedDevices {
unassignedDevices { id device name size type }
}
""",
"log_files": """
query ListLogFiles {
logFiles { name path size modifiedAt }
@@ -60,7 +54,6 @@ STORAGE_ACTIONS = Literal[
"shares",
"disks",
"disk_details",
"unassigned",
"log_files",
"logs",
]
@@ -97,7 +90,6 @@ def register_storage_tool(mcp: FastMCP) -> None:
shares - List all user shares with capacity info
disks - List all physical disks
disk_details - Detailed SMART info for a disk (requires disk_id)
unassigned - List unassigned devices
log_files - List available log files
logs - Retrieve log content (requires log_path, optional tail_lines)
"""
@@ -158,10 +150,6 @@ def register_storage_tool(mcp: FastMCP) -> None:
}
return {"summary": summary, "details": raw}
if action == "unassigned":
devices = data.get("unassignedDevices", [])
return {"devices": list(devices) if isinstance(devices, list) else []}
if action == "log_files":
files = data.get("logFiles", [])
return {"log_files": list(files) if isinstance(files, list) else []}