mirror of
https://github.com/jmagar/unraid-mcp
synced 2026-04-21 13:37:53 +00:00
fix: address PR #12 review comments on refactored tool files
- Add 'logs' to _DOCKER_SUBACTIONS so the validation guard passes through to the informative ToolError rather than a generic 'Invalid action' (P1) - Add inline comments to _SYSTEM_QUERIES explaining that 'network' and 'variables' share the vars root field but fetch different subfields (P3) - Process system/server response into a structured summary dict instead of returning raw GraphQL data directly (P3)
This commit is contained in:
parent
a0d23b8661
commit
f4adb4e8b9
2 changed files with 29 additions and 2 deletions
|
|
@ -31,7 +31,10 @@ _DOCKER_MUTATIONS: dict[str, str] = {
|
|||
"stop": "mutation StopContainer($id: PrefixedID!) { docker { stop(id: $id) { id names state status } } }",
|
||||
}
|
||||
|
||||
_DOCKER_SUBACTIONS: set[str] = set(_DOCKER_QUERIES) | set(_DOCKER_MUTATIONS) | {"restart"}
|
||||
# "logs" has no GraphQL query (field removed in Unraid 7.2.x) but is still a
|
||||
# recognised subaction so validation passes and the informative ToolError below
|
||||
# is returned rather than a generic "Invalid action" message.
|
||||
_DOCKER_SUBACTIONS: set[str] = set(_DOCKER_QUERIES) | set(_DOCKER_MUTATIONS) | {"restart", "logs"}
|
||||
_DOCKER_NEEDS_CONTAINER_ID = {"start", "stop", "details", "restart"}
|
||||
_DOCKER_ID_PATTERN = re.compile(r"^[a-f0-9]{64}(:[a-z0-9]+)?$", re.IGNORECASE)
|
||||
_DOCKER_SHORT_ID_PATTERN = re.compile(r"^[a-f0-9]{12,63}$", re.IGNORECASE)
|
||||
|
|
@ -131,6 +134,13 @@ async def _handle_docker(
|
|||
return dict(net)
|
||||
raise ToolError(f"Network '{network_id}' not found.")
|
||||
|
||||
if subaction == "logs":
|
||||
raise ToolError(
|
||||
"Container logs are not available via the Unraid GraphQL API. "
|
||||
"Use the Unraid terminal or SSH to run: "
|
||||
f"`docker logs {container_id or '<container_id>'} --tail 100`"
|
||||
)
|
||||
|
||||
if subaction == "restart":
|
||||
actual_id = await _resolve_container_id(container_id or "", strict=True)
|
||||
stop_data = await _client.make_graphql_request(
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ _SYSTEM_QUERIES: dict[str, str] = {
|
|||
}
|
||||
}
|
||||
""",
|
||||
# Uses the vars root field — returns only the network-access subset
|
||||
# (port, portssl, localTld, useSsl) alongside servers for URL construction.
|
||||
"network": """
|
||||
query GetNetworkInfo {
|
||||
servers { id name status wanip lanip localurl remoteurl }
|
||||
|
|
@ -54,6 +56,9 @@ _SYSTEM_QUERIES: dict[str, str] = {
|
|||
registration { id type keyFile { location } state expiration updateExpiration }
|
||||
}
|
||||
""",
|
||||
# Uses the vars root field — returns a broad subset of system variables.
|
||||
# Shares the same GraphQL root as "network" but requests a different field
|
||||
# set; no overlap occurs because GraphQL returns only the requested subfields.
|
||||
"variables": """
|
||||
query GetSelectiveUnraidVariables {
|
||||
vars {
|
||||
|
|
@ -206,7 +211,19 @@ async def _handle_system(subaction: str, device_id: str | None) -> dict[str, Any
|
|||
values = settings["unified"].get("values") or {}
|
||||
return dict(values) if isinstance(values, dict) else {"raw": values}
|
||||
if subaction == "server":
|
||||
return data
|
||||
info = data.get("info") or {}
|
||||
summary: dict[str, Any] = {}
|
||||
if info.get("os"):
|
||||
summary["hostname"] = info["os"].get("hostname")
|
||||
summary["uptime"] = info["os"].get("uptime")
|
||||
if info.get("versions") and info["versions"].get("core"):
|
||||
summary["unraid_version"] = info["versions"]["core"].get("unraid")
|
||||
summary["machine_id"] = info.get("machineId")
|
||||
summary["time"] = info.get("time")
|
||||
array = data.get("array") or {}
|
||||
summary["array_state"] = array.get("state")
|
||||
summary["online"] = data.get("online")
|
||||
return summary
|
||||
if subaction == "network":
|
||||
servers_data = data.get("servers") or []
|
||||
vars_data = data.get("vars") or {}
|
||||
|
|
|
|||
Loading…
Reference in a new issue