mirror of
https://github.com/jmagar/unraid-mcp.git
synced 2026-03-23 12:39:24 -07:00
fix(elicitation): guard ctx=None in elicit_and_configure, cover all settings/docker/notifications actions
- setup.py: elicit_and_configure now accepts Context | None; returns False immediately when ctx is None instead of crashing with AttributeError - settings.py: added CredentialsNotConfiguredError try/except guard around make_graphql_request calls in all 8 previously-unguarded actions (update_temperature, update_time, configure_ups, update_api, connect_sign_in, connect_sign_out, setup_remote_access, enable_dynamic_remote_access) - docker.py: added guards to all 20 previously-unguarded make_graphql_request calls (details, logs, networks, network_details, port_conflicts, check_updates, restart, update_all, all 11 organizer mutations, and single-container fallback) - notifications.py: added guards to all 11 previously-unguarded calls (list, warnings, create, archive/unread, delete, delete_archived, archive_all, archive_many, create_unique, unarchive_many, unarchive_all, recalculate)
This commit is contained in:
@@ -21,15 +21,26 @@ class _UnraidCredentials:
|
|||||||
api_key: str
|
api_key: str
|
||||||
|
|
||||||
|
|
||||||
async def elicit_and_configure(ctx: Context) -> bool:
|
async def elicit_and_configure(ctx: Context | None) -> bool:
|
||||||
"""Prompt the user for Unraid credentials via MCP elicitation.
|
"""Prompt the user for Unraid credentials via MCP elicitation.
|
||||||
|
|
||||||
Writes accepted credentials to .env in PROJECT_ROOT and applies them
|
Writes accepted credentials to .env in PROJECT_ROOT and applies them
|
||||||
to the running process via apply_runtime_config().
|
to the running process via apply_runtime_config().
|
||||||
|
|
||||||
|
Args:
|
||||||
|
ctx: The MCP context for elicitation. If None, returns False immediately
|
||||||
|
(no context available to prompt the user).
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
True if credentials were accepted and applied, False if declined/cancelled.
|
True if credentials were accepted and applied, False if declined/cancelled.
|
||||||
"""
|
"""
|
||||||
|
if ctx is None:
|
||||||
|
logger.warning(
|
||||||
|
"Cannot elicit credentials: no MCP context available. "
|
||||||
|
"Run unraid_health action=setup to configure credentials."
|
||||||
|
)
|
||||||
|
return False
|
||||||
|
|
||||||
result = await ctx.elicit(
|
result = await ctx.elicit(
|
||||||
message=(
|
message=(
|
||||||
"Unraid MCP needs your Unraid server credentials to connect.\n\n"
|
"Unraid MCP needs your Unraid server credentials to connect.\n\n"
|
||||||
|
|||||||
@@ -453,7 +453,15 @@ def register_docker_tool(mcp: FastMCP) -> None:
|
|||||||
if action == "details":
|
if action == "details":
|
||||||
# Resolve name -> ID first (skips list fetch if already an ID)
|
# Resolve name -> ID first (skips list fetch if already an ID)
|
||||||
actual_id = await _resolve_container_id(container_id or "")
|
actual_id = await _resolve_container_id(container_id or "")
|
||||||
data = await make_graphql_request(QUERIES["details"])
|
try:
|
||||||
|
data = await make_graphql_request(QUERIES["details"])
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(QUERIES["details"])
|
||||||
containers = safe_get(data, "docker", "containers", default=[])
|
containers = safe_get(data, "docker", "containers", default=[])
|
||||||
# Match by resolved ID (exact match, no second list fetch needed)
|
# Match by resolved ID (exact match, no second list fetch needed)
|
||||||
for c in containers:
|
for c in containers:
|
||||||
@@ -463,9 +471,19 @@ def register_docker_tool(mcp: FastMCP) -> None:
|
|||||||
|
|
||||||
if action == "logs":
|
if action == "logs":
|
||||||
actual_id = await _resolve_container_id(container_id or "")
|
actual_id = await _resolve_container_id(container_id or "")
|
||||||
data = await make_graphql_request(
|
try:
|
||||||
QUERIES["logs"], {"id": actual_id, "tail": tail_lines}
|
data = await make_graphql_request(
|
||||||
)
|
QUERIES["logs"], {"id": actual_id, "tail": tail_lines}
|
||||||
|
)
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(
|
||||||
|
QUERIES["logs"], {"id": actual_id, "tail": tail_lines}
|
||||||
|
)
|
||||||
logs_data = safe_get(data, "docker", "logs")
|
logs_data = safe_get(data, "docker", "logs")
|
||||||
if logs_data is None:
|
if logs_data is None:
|
||||||
raise ToolError(f"No logs returned for container '{container_id}'")
|
raise ToolError(f"No logs returned for container '{container_id}'")
|
||||||
@@ -483,12 +501,28 @@ def register_docker_tool(mcp: FastMCP) -> None:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if action == "networks":
|
if action == "networks":
|
||||||
data = await make_graphql_request(QUERIES["networks"])
|
try:
|
||||||
|
data = await make_graphql_request(QUERIES["networks"])
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(QUERIES["networks"])
|
||||||
networks = safe_get(data, "docker", "networks", default=[])
|
networks = safe_get(data, "docker", "networks", default=[])
|
||||||
return {"networks": networks}
|
return {"networks": networks}
|
||||||
|
|
||||||
if action == "network_details":
|
if action == "network_details":
|
||||||
data = await make_graphql_request(QUERIES["network_details"])
|
try:
|
||||||
|
data = await make_graphql_request(QUERIES["network_details"])
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(QUERIES["network_details"])
|
||||||
all_networks = safe_get(data, "docker", "networks", default=[])
|
all_networks = safe_get(data, "docker", "networks", default=[])
|
||||||
# Filter client-side by network_id since the API returns all networks
|
# Filter client-side by network_id since the API returns all networks
|
||||||
for net in all_networks:
|
for net in all_networks:
|
||||||
@@ -497,7 +531,15 @@ def register_docker_tool(mcp: FastMCP) -> None:
|
|||||||
raise ToolError(f"Network '{network_id}' not found.")
|
raise ToolError(f"Network '{network_id}' not found.")
|
||||||
|
|
||||||
if action == "port_conflicts":
|
if action == "port_conflicts":
|
||||||
data = await make_graphql_request(QUERIES["port_conflicts"])
|
try:
|
||||||
|
data = await make_graphql_request(QUERIES["port_conflicts"])
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(QUERIES["port_conflicts"])
|
||||||
conflicts_data = safe_get(data, "docker", "portConflicts", default={})
|
conflicts_data = safe_get(data, "docker", "portConflicts", default={})
|
||||||
# The GraphQL response is { containerPorts: [...], lanPorts: [...] }
|
# The GraphQL response is { containerPorts: [...], lanPorts: [...] }
|
||||||
# but callers expect result["port_conflicts"] to be a flat list.
|
# but callers expect result["port_conflicts"] to be a flat list.
|
||||||
@@ -511,7 +553,15 @@ def register_docker_tool(mcp: FastMCP) -> None:
|
|||||||
return {"port_conflicts": conflicts}
|
return {"port_conflicts": conflicts}
|
||||||
|
|
||||||
if action == "check_updates":
|
if action == "check_updates":
|
||||||
data = await make_graphql_request(QUERIES["check_updates"])
|
try:
|
||||||
|
data = await make_graphql_request(QUERIES["check_updates"])
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(QUERIES["check_updates"])
|
||||||
statuses = safe_get(data, "docker", "containerUpdateStatuses", default=[])
|
statuses = safe_get(data, "docker", "containerUpdateStatuses", default=[])
|
||||||
return {"update_statuses": statuses}
|
return {"update_statuses": statuses}
|
||||||
|
|
||||||
@@ -519,11 +569,23 @@ def register_docker_tool(mcp: FastMCP) -> None:
|
|||||||
if action == "restart":
|
if action == "restart":
|
||||||
actual_id = await _resolve_container_id(container_id or "", strict=True)
|
actual_id = await _resolve_container_id(container_id or "", strict=True)
|
||||||
# Stop (idempotent: treat "already stopped" as success)
|
# Stop (idempotent: treat "already stopped" as success)
|
||||||
stop_data = await make_graphql_request(
|
try:
|
||||||
MUTATIONS["stop"],
|
stop_data = await make_graphql_request(
|
||||||
{"id": actual_id},
|
MUTATIONS["stop"],
|
||||||
operation_context={"operation": "stop"},
|
{"id": actual_id},
|
||||||
)
|
operation_context={"operation": "stop"},
|
||||||
|
)
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
stop_data = await make_graphql_request(
|
||||||
|
MUTATIONS["stop"],
|
||||||
|
{"id": actual_id},
|
||||||
|
operation_context={"operation": "stop"},
|
||||||
|
)
|
||||||
stop_was_idempotent = stop_data.get("idempotent_success", False)
|
stop_was_idempotent = stop_data.get("idempotent_success", False)
|
||||||
# Start (idempotent: treat "already running" as success)
|
# Start (idempotent: treat "already running" as success)
|
||||||
start_data = await make_graphql_request(
|
start_data = await make_graphql_request(
|
||||||
@@ -545,7 +607,15 @@ def register_docker_tool(mcp: FastMCP) -> None:
|
|||||||
return response
|
return response
|
||||||
|
|
||||||
if action == "update_all":
|
if action == "update_all":
|
||||||
data = await make_graphql_request(MUTATIONS["update_all"])
|
try:
|
||||||
|
data = await make_graphql_request(MUTATIONS["update_all"])
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(MUTATIONS["update_all"])
|
||||||
results = safe_get(data, "docker", "updateAllContainers", default=[])
|
results = safe_get(data, "docker", "updateAllContainers", default=[])
|
||||||
return {"success": True, "action": "update_all", "containers": results}
|
return {"success": True, "action": "update_all", "containers": results}
|
||||||
|
|
||||||
@@ -558,7 +628,15 @@ def register_docker_tool(mcp: FastMCP) -> None:
|
|||||||
_vars["parentId"] = parent_id
|
_vars["parentId"] = parent_id
|
||||||
if children_ids is not None:
|
if children_ids is not None:
|
||||||
_vars["childrenIds"] = children_ids
|
_vars["childrenIds"] = children_ids
|
||||||
data = await make_graphql_request(MUTATIONS["create_folder"], _vars)
|
try:
|
||||||
|
data = await make_graphql_request(MUTATIONS["create_folder"], _vars)
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(MUTATIONS["create_folder"], _vars)
|
||||||
organizer = data.get("createDockerFolder")
|
organizer = data.get("createDockerFolder")
|
||||||
if organizer is None:
|
if organizer is None:
|
||||||
raise ToolError("create_folder failed: server returned no data")
|
raise ToolError("create_folder failed: server returned no data")
|
||||||
@@ -570,7 +648,15 @@ def register_docker_tool(mcp: FastMCP) -> None:
|
|||||||
_vars = {"childrenIds": children_ids}
|
_vars = {"childrenIds": children_ids}
|
||||||
if folder_id is not None:
|
if folder_id is not None:
|
||||||
_vars["folderId"] = folder_id
|
_vars["folderId"] = folder_id
|
||||||
data = await make_graphql_request(MUTATIONS["set_folder_children"], _vars)
|
try:
|
||||||
|
data = await make_graphql_request(MUTATIONS["set_folder_children"], _vars)
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(MUTATIONS["set_folder_children"], _vars)
|
||||||
organizer = data.get("setDockerFolderChildren")
|
organizer = data.get("setDockerFolderChildren")
|
||||||
if organizer is None:
|
if organizer is None:
|
||||||
raise ToolError("set_folder_children failed: server returned no data")
|
raise ToolError("set_folder_children failed: server returned no data")
|
||||||
@@ -579,9 +665,19 @@ def register_docker_tool(mcp: FastMCP) -> None:
|
|||||||
if action == "delete_entries":
|
if action == "delete_entries":
|
||||||
if not entry_ids:
|
if not entry_ids:
|
||||||
raise ToolError("entry_ids is required for 'delete_entries' action")
|
raise ToolError("entry_ids is required for 'delete_entries' action")
|
||||||
data = await make_graphql_request(
|
try:
|
||||||
MUTATIONS["delete_entries"], {"entryIds": entry_ids}
|
data = await make_graphql_request(
|
||||||
)
|
MUTATIONS["delete_entries"], {"entryIds": entry_ids}
|
||||||
|
)
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(
|
||||||
|
MUTATIONS["delete_entries"], {"entryIds": entry_ids}
|
||||||
|
)
|
||||||
organizer = data.get("deleteDockerEntries")
|
organizer = data.get("deleteDockerEntries")
|
||||||
if organizer is None:
|
if organizer is None:
|
||||||
raise ToolError("delete_entries failed: server returned no data")
|
raise ToolError("delete_entries failed: server returned no data")
|
||||||
@@ -592,13 +688,19 @@ def register_docker_tool(mcp: FastMCP) -> None:
|
|||||||
raise ToolError("source_entry_ids is required for 'move_to_folder' action")
|
raise ToolError("source_entry_ids is required for 'move_to_folder' action")
|
||||||
if not destination_folder_id:
|
if not destination_folder_id:
|
||||||
raise ToolError("destination_folder_id is required for 'move_to_folder' action")
|
raise ToolError("destination_folder_id is required for 'move_to_folder' action")
|
||||||
data = await make_graphql_request(
|
_move_vars = {
|
||||||
MUTATIONS["move_to_folder"],
|
"sourceEntryIds": source_entry_ids,
|
||||||
{
|
"destinationFolderId": destination_folder_id,
|
||||||
"sourceEntryIds": source_entry_ids,
|
}
|
||||||
"destinationFolderId": destination_folder_id,
|
try:
|
||||||
},
|
data = await make_graphql_request(MUTATIONS["move_to_folder"], _move_vars)
|
||||||
)
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(MUTATIONS["move_to_folder"], _move_vars)
|
||||||
organizer = data.get("moveDockerEntriesToFolder")
|
organizer = data.get("moveDockerEntriesToFolder")
|
||||||
if organizer is None:
|
if organizer is None:
|
||||||
raise ToolError("move_to_folder failed: server returned no data")
|
raise ToolError("move_to_folder failed: server returned no data")
|
||||||
@@ -613,14 +715,20 @@ def register_docker_tool(mcp: FastMCP) -> None:
|
|||||||
)
|
)
|
||||||
if position is None:
|
if position is None:
|
||||||
raise ToolError("position is required for 'move_to_position' action")
|
raise ToolError("position is required for 'move_to_position' action")
|
||||||
data = await make_graphql_request(
|
_mtp_vars = {
|
||||||
MUTATIONS["move_to_position"],
|
"sourceEntryIds": source_entry_ids,
|
||||||
{
|
"destinationFolderId": destination_folder_id,
|
||||||
"sourceEntryIds": source_entry_ids,
|
"position": position,
|
||||||
"destinationFolderId": destination_folder_id,
|
}
|
||||||
"position": position,
|
try:
|
||||||
},
|
data = await make_graphql_request(MUTATIONS["move_to_position"], _mtp_vars)
|
||||||
)
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(MUTATIONS["move_to_position"], _mtp_vars)
|
||||||
organizer = data.get("moveDockerItemsToPosition")
|
organizer = data.get("moveDockerItemsToPosition")
|
||||||
if organizer is None:
|
if organizer is None:
|
||||||
raise ToolError("move_to_position failed: server returned no data")
|
raise ToolError("move_to_position failed: server returned no data")
|
||||||
@@ -631,9 +739,16 @@ def register_docker_tool(mcp: FastMCP) -> None:
|
|||||||
raise ToolError("folder_id is required for 'rename_folder' action")
|
raise ToolError("folder_id is required for 'rename_folder' action")
|
||||||
if not new_folder_name:
|
if not new_folder_name:
|
||||||
raise ToolError("new_folder_name is required for 'rename_folder' action")
|
raise ToolError("new_folder_name is required for 'rename_folder' action")
|
||||||
data = await make_graphql_request(
|
_rf_vars = {"folderId": folder_id, "newName": new_folder_name}
|
||||||
MUTATIONS["rename_folder"], {"folderId": folder_id, "newName": new_folder_name}
|
try:
|
||||||
)
|
data = await make_graphql_request(MUTATIONS["rename_folder"], _rf_vars)
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(MUTATIONS["rename_folder"], _rf_vars)
|
||||||
organizer = data.get("renameDockerFolder")
|
organizer = data.get("renameDockerFolder")
|
||||||
if organizer is None:
|
if organizer is None:
|
||||||
raise ToolError("rename_folder failed: server returned no data")
|
raise ToolError("rename_folder failed: server returned no data")
|
||||||
@@ -649,7 +764,15 @@ def register_docker_tool(mcp: FastMCP) -> None:
|
|||||||
_vars["sourceEntryIds"] = source_entry_ids
|
_vars["sourceEntryIds"] = source_entry_ids
|
||||||
if position is not None:
|
if position is not None:
|
||||||
_vars["position"] = position
|
_vars["position"] = position
|
||||||
data = await make_graphql_request(MUTATIONS["create_folder_with_items"], _vars)
|
try:
|
||||||
|
data = await make_graphql_request(MUTATIONS["create_folder_with_items"], _vars)
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(MUTATIONS["create_folder_with_items"], _vars)
|
||||||
organizer = data.get("createDockerFolderWithItems")
|
organizer = data.get("createDockerFolderWithItems")
|
||||||
if organizer is None:
|
if organizer is None:
|
||||||
raise ToolError("create_folder_with_items failed: server returned no data")
|
raise ToolError("create_folder_with_items failed: server returned no data")
|
||||||
@@ -662,23 +785,46 @@ def register_docker_tool(mcp: FastMCP) -> None:
|
|||||||
if action == "update_view_prefs":
|
if action == "update_view_prefs":
|
||||||
if view_prefs is None:
|
if view_prefs is None:
|
||||||
raise ToolError("view_prefs is required for 'update_view_prefs' action")
|
raise ToolError("view_prefs is required for 'update_view_prefs' action")
|
||||||
data = await make_graphql_request(
|
_uvp_vars = {"viewId": view_id, "prefs": view_prefs}
|
||||||
MUTATIONS["update_view_prefs"], {"viewId": view_id, "prefs": view_prefs}
|
try:
|
||||||
)
|
data = await make_graphql_request(MUTATIONS["update_view_prefs"], _uvp_vars)
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(MUTATIONS["update_view_prefs"], _uvp_vars)
|
||||||
organizer = data.get("updateDockerViewPreferences")
|
organizer = data.get("updateDockerViewPreferences")
|
||||||
if organizer is None:
|
if organizer is None:
|
||||||
raise ToolError("update_view_prefs failed: server returned no data")
|
raise ToolError("update_view_prefs failed: server returned no data")
|
||||||
return {"success": True, "action": "update_view_prefs", "organizer": organizer}
|
return {"success": True, "action": "update_view_prefs", "organizer": organizer}
|
||||||
|
|
||||||
if action == "sync_templates":
|
if action == "sync_templates":
|
||||||
data = await make_graphql_request(MUTATIONS["sync_templates"])
|
try:
|
||||||
|
data = await make_graphql_request(MUTATIONS["sync_templates"])
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(MUTATIONS["sync_templates"])
|
||||||
result = data.get("syncDockerTemplatePaths")
|
result = data.get("syncDockerTemplatePaths")
|
||||||
if result is None:
|
if result is None:
|
||||||
raise ToolError("sync_templates failed: server returned no data")
|
raise ToolError("sync_templates failed: server returned no data")
|
||||||
return {"success": True, "action": "sync_templates", "result": result}
|
return {"success": True, "action": "sync_templates", "result": result}
|
||||||
|
|
||||||
if action == "reset_template_mappings":
|
if action == "reset_template_mappings":
|
||||||
data = await make_graphql_request(MUTATIONS["reset_template_mappings"])
|
try:
|
||||||
|
data = await make_graphql_request(MUTATIONS["reset_template_mappings"])
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(MUTATIONS["reset_template_mappings"])
|
||||||
return {
|
return {
|
||||||
"success": True,
|
"success": True,
|
||||||
"action": "reset_template_mappings",
|
"action": "reset_template_mappings",
|
||||||
@@ -686,7 +832,15 @@ def register_docker_tool(mcp: FastMCP) -> None:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if action == "refresh_digests":
|
if action == "refresh_digests":
|
||||||
data = await make_graphql_request(MUTATIONS["refresh_digests"])
|
try:
|
||||||
|
data = await make_graphql_request(MUTATIONS["refresh_digests"])
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(MUTATIONS["refresh_digests"])
|
||||||
return {
|
return {
|
||||||
"success": True,
|
"success": True,
|
||||||
"action": "refresh_digests",
|
"action": "refresh_digests",
|
||||||
@@ -699,11 +853,23 @@ def register_docker_tool(mcp: FastMCP) -> None:
|
|||||||
op_context: dict[str, str] | None = (
|
op_context: dict[str, str] | None = (
|
||||||
{"operation": action} if action in ("start", "stop") else None
|
{"operation": action} if action in ("start", "stop") else None
|
||||||
)
|
)
|
||||||
data = await make_graphql_request(
|
try:
|
||||||
MUTATIONS[action],
|
data = await make_graphql_request(
|
||||||
{"id": actual_id},
|
MUTATIONS[action],
|
||||||
operation_context=op_context,
|
{"id": actual_id},
|
||||||
)
|
operation_context=op_context,
|
||||||
|
)
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(
|
||||||
|
MUTATIONS[action],
|
||||||
|
{"id": actual_id},
|
||||||
|
operation_context=op_context,
|
||||||
|
)
|
||||||
|
|
||||||
# Handle idempotent success
|
# Handle idempotent success
|
||||||
if data.get("idempotent_success"):
|
if data.get("idempotent_success"):
|
||||||
|
|||||||
@@ -248,12 +248,28 @@ def register_notifications_tool(mcp: FastMCP) -> None:
|
|||||||
}
|
}
|
||||||
if importance:
|
if importance:
|
||||||
filter_vars["importance"] = importance.upper()
|
filter_vars["importance"] = importance.upper()
|
||||||
data = await make_graphql_request(QUERIES["list"], {"filter": filter_vars})
|
try:
|
||||||
|
data = await make_graphql_request(QUERIES["list"], {"filter": filter_vars})
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(QUERIES["list"], {"filter": filter_vars})
|
||||||
notifications = data.get("notifications", {})
|
notifications = data.get("notifications", {})
|
||||||
return {"notifications": notifications.get("list", [])}
|
return {"notifications": notifications.get("list", [])}
|
||||||
|
|
||||||
if action == "warnings":
|
if action == "warnings":
|
||||||
data = await make_graphql_request(QUERIES["warnings"])
|
try:
|
||||||
|
data = await make_graphql_request(QUERIES["warnings"])
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(QUERIES["warnings"])
|
||||||
notifications = data.get("notifications", {})
|
notifications = data.get("notifications", {})
|
||||||
return {"warnings": notifications.get("warningsAndAlerts", [])}
|
return {"warnings": notifications.get("warningsAndAlerts", [])}
|
||||||
|
|
||||||
@@ -279,7 +295,15 @@ def register_notifications_tool(mcp: FastMCP) -> None:
|
|||||||
"description": description,
|
"description": description,
|
||||||
"importance": importance.upper(),
|
"importance": importance.upper(),
|
||||||
}
|
}
|
||||||
data = await make_graphql_request(MUTATIONS["create"], {"input": input_data})
|
try:
|
||||||
|
data = await make_graphql_request(MUTATIONS["create"], {"input": input_data})
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(MUTATIONS["create"], {"input": input_data})
|
||||||
notification = data.get("createNotification")
|
notification = data.get("createNotification")
|
||||||
if notification is None:
|
if notification is None:
|
||||||
raise ToolError("Notification creation failed: server returned no data")
|
raise ToolError("Notification creation failed: server returned no data")
|
||||||
@@ -288,35 +312,75 @@ def register_notifications_tool(mcp: FastMCP) -> None:
|
|||||||
if action in ("archive", "unread"):
|
if action in ("archive", "unread"):
|
||||||
if not notification_id:
|
if not notification_id:
|
||||||
raise ToolError(f"notification_id is required for '{action}' action")
|
raise ToolError(f"notification_id is required for '{action}' action")
|
||||||
data = await make_graphql_request(MUTATIONS[action], {"id": notification_id})
|
try:
|
||||||
|
data = await make_graphql_request(MUTATIONS[action], {"id": notification_id})
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(MUTATIONS[action], {"id": notification_id})
|
||||||
return {"success": True, "action": action, "data": data}
|
return {"success": True, "action": action, "data": data}
|
||||||
|
|
||||||
if action == "delete":
|
if action == "delete":
|
||||||
if not notification_id or not notification_type:
|
if not notification_id or not notification_type:
|
||||||
raise ToolError("delete requires notification_id and notification_type")
|
raise ToolError("delete requires notification_id and notification_type")
|
||||||
data = await make_graphql_request(
|
_del_vars = {"id": notification_id, "type": notification_type.upper()}
|
||||||
MUTATIONS["delete"],
|
try:
|
||||||
{"id": notification_id, "type": notification_type.upper()},
|
data = await make_graphql_request(MUTATIONS["delete"], _del_vars)
|
||||||
)
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(MUTATIONS["delete"], _del_vars)
|
||||||
return {"success": True, "action": "delete", "data": data}
|
return {"success": True, "action": "delete", "data": data}
|
||||||
|
|
||||||
if action == "delete_archived":
|
if action == "delete_archived":
|
||||||
data = await make_graphql_request(MUTATIONS["delete_archived"])
|
try:
|
||||||
|
data = await make_graphql_request(MUTATIONS["delete_archived"])
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(MUTATIONS["delete_archived"])
|
||||||
return {"success": True, "action": "delete_archived", "data": data}
|
return {"success": True, "action": "delete_archived", "data": data}
|
||||||
|
|
||||||
if action == "archive_all":
|
if action == "archive_all":
|
||||||
variables: dict[str, Any] | None = None
|
variables: dict[str, Any] | None = None
|
||||||
if importance:
|
if importance:
|
||||||
variables = {"importance": importance.upper()}
|
variables = {"importance": importance.upper()}
|
||||||
data = await make_graphql_request(MUTATIONS["archive_all"], variables)
|
try:
|
||||||
|
data = await make_graphql_request(MUTATIONS["archive_all"], variables)
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(MUTATIONS["archive_all"], variables)
|
||||||
return {"success": True, "action": "archive_all", "data": data}
|
return {"success": True, "action": "archive_all", "data": data}
|
||||||
|
|
||||||
if action == "archive_many":
|
if action == "archive_many":
|
||||||
if not notification_ids:
|
if not notification_ids:
|
||||||
raise ToolError("notification_ids is required for 'archive_many' action")
|
raise ToolError("notification_ids is required for 'archive_many' action")
|
||||||
data = await make_graphql_request(
|
try:
|
||||||
MUTATIONS["archive_many"], {"ids": notification_ids}
|
data = await make_graphql_request(
|
||||||
)
|
MUTATIONS["archive_many"], {"ids": notification_ids}
|
||||||
|
)
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(
|
||||||
|
MUTATIONS["archive_many"], {"ids": notification_ids}
|
||||||
|
)
|
||||||
return {"success": True, "action": "archive_many", "data": data}
|
return {"success": True, "action": "archive_many", "data": data}
|
||||||
|
|
||||||
if action == "create_unique":
|
if action == "create_unique":
|
||||||
@@ -343,7 +407,19 @@ def register_notifications_tool(mcp: FastMCP) -> None:
|
|||||||
"description": description,
|
"description": description,
|
||||||
"importance": importance.upper(),
|
"importance": importance.upper(),
|
||||||
}
|
}
|
||||||
data = await make_graphql_request(MUTATIONS["create_unique"], {"input": input_data})
|
try:
|
||||||
|
data = await make_graphql_request(
|
||||||
|
MUTATIONS["create_unique"], {"input": input_data}
|
||||||
|
)
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(
|
||||||
|
MUTATIONS["create_unique"], {"input": input_data}
|
||||||
|
)
|
||||||
notification = data.get("notifyIfUnique")
|
notification = data.get("notifyIfUnique")
|
||||||
if notification is None:
|
if notification is None:
|
||||||
return {"success": True, "duplicate": True, "data": None}
|
return {"success": True, "duplicate": True, "data": None}
|
||||||
@@ -352,20 +428,46 @@ def register_notifications_tool(mcp: FastMCP) -> None:
|
|||||||
if action == "unarchive_many":
|
if action == "unarchive_many":
|
||||||
if not notification_ids:
|
if not notification_ids:
|
||||||
raise ToolError("notification_ids is required for 'unarchive_many' action")
|
raise ToolError("notification_ids is required for 'unarchive_many' action")
|
||||||
data = await make_graphql_request(
|
try:
|
||||||
MUTATIONS["unarchive_many"], {"ids": notification_ids}
|
data = await make_graphql_request(
|
||||||
)
|
MUTATIONS["unarchive_many"], {"ids": notification_ids}
|
||||||
|
)
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(
|
||||||
|
MUTATIONS["unarchive_many"], {"ids": notification_ids}
|
||||||
|
)
|
||||||
return {"success": True, "action": "unarchive_many", "data": data}
|
return {"success": True, "action": "unarchive_many", "data": data}
|
||||||
|
|
||||||
if action == "unarchive_all":
|
if action == "unarchive_all":
|
||||||
vars_: dict[str, Any] | None = None
|
vars_: dict[str, Any] | None = None
|
||||||
if importance:
|
if importance:
|
||||||
vars_ = {"importance": importance.upper()}
|
vars_ = {"importance": importance.upper()}
|
||||||
data = await make_graphql_request(MUTATIONS["unarchive_all"], vars_)
|
try:
|
||||||
|
data = await make_graphql_request(MUTATIONS["unarchive_all"], vars_)
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(MUTATIONS["unarchive_all"], vars_)
|
||||||
return {"success": True, "action": "unarchive_all", "data": data}
|
return {"success": True, "action": "unarchive_all", "data": data}
|
||||||
|
|
||||||
if action == "recalculate":
|
if action == "recalculate":
|
||||||
data = await make_graphql_request(MUTATIONS["recalculate"])
|
try:
|
||||||
|
data = await make_graphql_request(MUTATIONS["recalculate"])
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(MUTATIONS["recalculate"])
|
||||||
return {"success": True, "action": "recalculate", "data": data}
|
return {"success": True, "action": "recalculate", "data": data}
|
||||||
|
|
||||||
raise ToolError(f"Unhandled action '{action}' — this is a bug")
|
raise ToolError(f"Unhandled action '{action}' — this is a bug")
|
||||||
|
|||||||
@@ -168,9 +168,19 @@ def register_settings_tool(mcp: FastMCP) -> None:
|
|||||||
raise ToolError(
|
raise ToolError(
|
||||||
"temperature_config is required for 'update_temperature' action"
|
"temperature_config is required for 'update_temperature' action"
|
||||||
)
|
)
|
||||||
data = await make_graphql_request(
|
try:
|
||||||
MUTATIONS["update_temperature"], {"input": temperature_config}
|
data = await make_graphql_request(
|
||||||
)
|
MUTATIONS["update_temperature"], {"input": temperature_config}
|
||||||
|
)
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(
|
||||||
|
MUTATIONS["update_temperature"], {"input": temperature_config}
|
||||||
|
)
|
||||||
return {
|
return {
|
||||||
"success": True,
|
"success": True,
|
||||||
"action": "update_temperature",
|
"action": "update_temperature",
|
||||||
@@ -191,7 +201,19 @@ def register_settings_tool(mcp: FastMCP) -> None:
|
|||||||
raise ToolError(
|
raise ToolError(
|
||||||
"update_time requires at least one of: time_zone, use_ntp, ntp_servers, manual_datetime"
|
"update_time requires at least one of: time_zone, use_ntp, ntp_servers, manual_datetime"
|
||||||
)
|
)
|
||||||
data = await make_graphql_request(MUTATIONS["update_time"], {"input": time_input})
|
try:
|
||||||
|
data = await make_graphql_request(
|
||||||
|
MUTATIONS["update_time"], {"input": time_input}
|
||||||
|
)
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(
|
||||||
|
MUTATIONS["update_time"], {"input": time_input}
|
||||||
|
)
|
||||||
return {
|
return {
|
||||||
"success": True,
|
"success": True,
|
||||||
"action": "update_time",
|
"action": "update_time",
|
||||||
@@ -201,9 +223,19 @@ def register_settings_tool(mcp: FastMCP) -> None:
|
|||||||
if action == "configure_ups":
|
if action == "configure_ups":
|
||||||
if ups_config is None:
|
if ups_config is None:
|
||||||
raise ToolError("ups_config is required for 'configure_ups' action")
|
raise ToolError("ups_config is required for 'configure_ups' action")
|
||||||
data = await make_graphql_request(
|
try:
|
||||||
MUTATIONS["configure_ups"], {"config": ups_config}
|
data = await make_graphql_request(
|
||||||
)
|
MUTATIONS["configure_ups"], {"config": ups_config}
|
||||||
|
)
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(
|
||||||
|
MUTATIONS["configure_ups"], {"config": ups_config}
|
||||||
|
)
|
||||||
return {
|
return {
|
||||||
"success": True,
|
"success": True,
|
||||||
"action": "configure_ups",
|
"action": "configure_ups",
|
||||||
@@ -222,7 +254,15 @@ def register_settings_tool(mcp: FastMCP) -> None:
|
|||||||
raise ToolError(
|
raise ToolError(
|
||||||
"update_api requires at least one of: access_type, forward_type, port"
|
"update_api requires at least one of: access_type, forward_type, port"
|
||||||
)
|
)
|
||||||
data = await make_graphql_request(MUTATIONS["update_api"], {"input": api_input})
|
try:
|
||||||
|
data = await make_graphql_request(MUTATIONS["update_api"], {"input": api_input})
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(MUTATIONS["update_api"], {"input": api_input})
|
||||||
return {
|
return {
|
||||||
"success": True,
|
"success": True,
|
||||||
"action": "update_api",
|
"action": "update_api",
|
||||||
@@ -242,9 +282,19 @@ def register_settings_tool(mcp: FastMCP) -> None:
|
|||||||
user_info["avatar"] = avatar
|
user_info["avatar"] = avatar
|
||||||
if user_info:
|
if user_info:
|
||||||
sign_in_input["userInfo"] = user_info
|
sign_in_input["userInfo"] = user_info
|
||||||
data = await make_graphql_request(
|
try:
|
||||||
MUTATIONS["connect_sign_in"], {"input": sign_in_input}
|
data = await make_graphql_request(
|
||||||
)
|
MUTATIONS["connect_sign_in"], {"input": sign_in_input}
|
||||||
|
)
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(
|
||||||
|
MUTATIONS["connect_sign_in"], {"input": sign_in_input}
|
||||||
|
)
|
||||||
return {
|
return {
|
||||||
"success": True,
|
"success": True,
|
||||||
"action": "connect_sign_in",
|
"action": "connect_sign_in",
|
||||||
@@ -252,7 +302,15 @@ def register_settings_tool(mcp: FastMCP) -> None:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if action == "connect_sign_out":
|
if action == "connect_sign_out":
|
||||||
data = await make_graphql_request(MUTATIONS["connect_sign_out"])
|
try:
|
||||||
|
data = await make_graphql_request(MUTATIONS["connect_sign_out"])
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(MUTATIONS["connect_sign_out"])
|
||||||
return {
|
return {
|
||||||
"success": True,
|
"success": True,
|
||||||
"action": "connect_sign_out",
|
"action": "connect_sign_out",
|
||||||
@@ -267,9 +325,19 @@ def register_settings_tool(mcp: FastMCP) -> None:
|
|||||||
remote_input["forwardType"] = forward_type
|
remote_input["forwardType"] = forward_type
|
||||||
if port is not None:
|
if port is not None:
|
||||||
remote_input["port"] = port
|
remote_input["port"] = port
|
||||||
data = await make_graphql_request(
|
try:
|
||||||
MUTATIONS["setup_remote_access"], {"input": remote_input}
|
data = await make_graphql_request(
|
||||||
)
|
MUTATIONS["setup_remote_access"], {"input": remote_input}
|
||||||
|
)
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(
|
||||||
|
MUTATIONS["setup_remote_access"], {"input": remote_input}
|
||||||
|
)
|
||||||
return {
|
return {
|
||||||
"success": True,
|
"success": True,
|
||||||
"action": "setup_remote_access",
|
"action": "setup_remote_access",
|
||||||
@@ -292,10 +360,22 @@ def register_settings_tool(mcp: FastMCP) -> None:
|
|||||||
url_input["ipv4"] = access_url_ipv4
|
url_input["ipv4"] = access_url_ipv4
|
||||||
if access_url_ipv6 is not None:
|
if access_url_ipv6 is not None:
|
||||||
url_input["ipv6"] = access_url_ipv6
|
url_input["ipv6"] = access_url_ipv6
|
||||||
data = await make_graphql_request(
|
dra_vars = {"input": {"url": url_input, "enabled": dynamic_enabled}}
|
||||||
MUTATIONS["enable_dynamic_remote_access"],
|
try:
|
||||||
{"input": {"url": url_input, "enabled": dynamic_enabled}},
|
data = await make_graphql_request(
|
||||||
)
|
MUTATIONS["enable_dynamic_remote_access"],
|
||||||
|
dra_vars,
|
||||||
|
)
|
||||||
|
except CredentialsNotConfiguredError:
|
||||||
|
configured = await elicit_and_configure(ctx)
|
||||||
|
if not configured:
|
||||||
|
raise ToolError(
|
||||||
|
"Credentials required. Run `unraid_health action=setup` to configure."
|
||||||
|
)
|
||||||
|
data = await make_graphql_request(
|
||||||
|
MUTATIONS["enable_dynamic_remote_access"],
|
||||||
|
dra_vars,
|
||||||
|
)
|
||||||
return {
|
return {
|
||||||
"success": True,
|
"success": True,
|
||||||
"action": "enable_dynamic_remote_access",
|
"action": "enable_dynamic_remote_access",
|
||||||
|
|||||||
Reference in New Issue
Block a user