forked from HomeLab/unraid-mcp
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 84675815b4 | |||
| 37013fbd81 | |||
| 202354bbc1 | |||
| 0d876564cc |
@@ -84,8 +84,8 @@ docker compose down
|
|||||||
- **Health Monitoring**: Comprehensive health check tool for system monitoring
|
- **Health Monitoring**: Comprehensive health check tool for system monitoring
|
||||||
- **Real-time Subscriptions**: WebSocket-based live data streaming
|
- **Real-time Subscriptions**: WebSocket-based live data streaming
|
||||||
|
|
||||||
### Tool Categories (9 Tools, 70 Actions)
|
### Tool Categories (9 Tools, 69 Actions)
|
||||||
1. **`unraid_info`** (19 actions): overview, array, network, registration, connect, variables, metrics, services, display, config, online, owner, settings, server, servers, flash, ups_devices, ups_device, ups_config
|
1. **`unraid_info`** (19 actions): overview, array, network, registration, connect, variables, metrics, services, display, config, online, owner, settings, server, servers, flash, ups_devices, ups_device
|
||||||
2. **`unraid_storage`** (6 actions): shares, disks, disk_details, log_files, logs
|
2. **`unraid_storage`** (6 actions): shares, disks, disk_details, log_files, logs
|
||||||
3. **`unraid_docker`** (15 actions): list, details, start, stop, restart, pause, unpause, remove, update, update_all, logs, networks, network_details, port_conflicts, check_updates
|
3. **`unraid_docker`** (15 actions): list, details, start, stop, restart, pause, unpause, remove, update, update_all, logs, networks, network_details, port_conflicts, check_updates
|
||||||
4. **`unraid_vm`** (9 actions): list, details, start, stop, pause, resume, force_stop, reboot, reset
|
4. **`unraid_vm`** (9 actions): list, details, start, stop, pause, resume, force_stop, reboot, reset
|
||||||
|
|||||||
22
HISTORY.md
22
HISTORY.md
@@ -5,11 +5,33 @@ Changelog
|
|||||||
(unreleased)
|
(unreleased)
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
Fix
|
||||||
|
~~~
|
||||||
|
- Even more schema apatations. [Simon Diesenreiter]
|
||||||
|
|
||||||
|
|
||||||
|
0.0.5 (2026-02-28)
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Fix
|
||||||
|
~~~
|
||||||
|
- Runtime error due to broken import. [Simon Diesenreiter]
|
||||||
|
|
||||||
|
Other
|
||||||
|
~~~~~
|
||||||
|
|
||||||
|
|
||||||
|
0.0.4 (2026-02-28)
|
||||||
|
------------------
|
||||||
|
|
||||||
Fix
|
Fix
|
||||||
~~~
|
~~~
|
||||||
- Even more changes to accommodate older GraphQL schema. [Simon
|
- Even more changes to accommodate older GraphQL schema. [Simon
|
||||||
Diesenreiter]
|
Diesenreiter]
|
||||||
|
|
||||||
|
Other
|
||||||
|
~~~~~
|
||||||
|
|
||||||
|
|
||||||
0.0.3 (2026-02-28)
|
0.0.3 (2026-02-28)
|
||||||
------------------
|
------------------
|
||||||
|
|||||||
@@ -218,11 +218,11 @@ UNRAID_VERIFY_SSL=true # true, false, or path to CA bundle
|
|||||||
|
|
||||||
Each tool uses a consolidated `action` parameter to expose multiple operations, reducing context window usage. Destructive actions require `confirm=True`.
|
Each tool uses a consolidated `action` parameter to expose multiple operations, reducing context window usage. Destructive actions require `confirm=True`.
|
||||||
|
|
||||||
### Tool Categories (9 Tools, 70 Actions)
|
### Tool Categories (9 Tools, 69 Actions)
|
||||||
|
|
||||||
| Tool | Actions | Description |
|
| Tool | Actions | Description |
|
||||||
|------|---------|-------------|
|
|------|---------|-------------|
|
||||||
| **`unraid_info`** | 19 | overview, array, network, registration, connect, variables, metrics, services, display, config, online, owner, settings, server, servers, flash, ups_devices, ups_device, ups_config |
|
| **`unraid_info`** | 19 | overview, array, network, registration, connect, variables, metrics, services, display, config, online, owner, settings, server, servers, flash, ups_devices, ups_device |
|
||||||
| **`unraid_storage`** | 6 | shares, disks, disk_details, log_files, logs |
|
| **`unraid_storage`** | 6 | shares, disks, disk_details, log_files, logs |
|
||||||
| **`unraid_docker`** | 15 | list, details, start, stop, restart, pause, unpause, remove, update, update_all, logs, networks, network_details, port_conflicts, check_updates |
|
| **`unraid_docker`** | 15 | list, details, start, stop, restart, pause, unpause, remove, update, update_all, logs, networks, network_details, port_conflicts, check_updates |
|
||||||
| **`unraid_vm`** | 9 | list, details, start, stop, pause, resume, force_stop, reboot, reset |
|
| **`unraid_vm`** | 9 | list, details, start, stop, pause, resume, force_stop, reboot, reset |
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ Execute the `unraid_info` MCP tool with action: `$1`
|
|||||||
- `metrics` - System metrics (CPU, RAM, disk I/O)
|
- `metrics` - System metrics (CPU, RAM, disk I/O)
|
||||||
- `ups_devices` - List all UPS devices
|
- `ups_devices` - List all UPS devices
|
||||||
- `ups_device` - Get specific UPS device details (requires device_id)
|
- `ups_device` - Get specific UPS device details (requires device_id)
|
||||||
- `ups_config` - UPS configuration
|
|
||||||
|
|
||||||
**Ownership:**
|
**Ownership:**
|
||||||
- `owner` - Server owner information
|
- `owner` - Server owner information
|
||||||
|
|||||||
@@ -564,7 +564,6 @@ The current MCP server has 10 tools (76 actions) after consolidation. The follow
|
|||||||
|--------------|---------------|---------------|
|
|--------------|---------------|---------------|
|
||||||
| `list_ups_devices()` | `upsDevices` query | UPS monitoring |
|
| `list_ups_devices()` | `upsDevices` query | UPS monitoring |
|
||||||
| `get_ups_device(id)` | `upsDeviceById` query | UPS details |
|
| `get_ups_device(id)` | `upsDeviceById` query | UPS details |
|
||||||
| `get_ups_configuration()` | `upsConfiguration` query | UPS config |
|
|
||||||
| `configure_ups(config)` | `configureUps` mutation | UPS management |
|
| `configure_ups(config)` | `configureUps` mutation | UPS management |
|
||||||
|
|
||||||
#### System Metrics (0 tools currently, 1 query + 3 subscriptions)
|
#### System Metrics (0 tools currently, 1 query + 3 subscriptions)
|
||||||
|
|||||||
@@ -1128,7 +1128,6 @@ type ApiKey implements Node {
|
|||||||
permissions: JSON
|
permissions: JSON
|
||||||
createdAt: String!
|
createdAt: String!
|
||||||
description: String
|
description: String
|
||||||
lastUsed: String
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ApiKeyMutations {
|
type ApiKeyMutations {
|
||||||
|
|||||||
@@ -142,12 +142,6 @@ class TestInfoQueries:
|
|||||||
errors = _validate_operation(schema, QUERIES["ups_device"])
|
errors = _validate_operation(schema, QUERIES["ups_device"])
|
||||||
assert not errors, f"ups_device query validation failed: {errors}"
|
assert not errors, f"ups_device query validation failed: {errors}"
|
||||||
|
|
||||||
def test_ups_config_query(self, schema: GraphQLSchema) -> None:
|
|
||||||
from unraid_mcp.tools.info import QUERIES
|
|
||||||
|
|
||||||
errors = _validate_operation(schema, QUERIES["ups_config"])
|
|
||||||
assert not errors, f"ups_config query validation failed: {errors}"
|
|
||||||
|
|
||||||
def test_all_info_actions_covered(self, schema: GraphQLSchema) -> None:
|
def test_all_info_actions_covered(self, schema: GraphQLSchema) -> None:
|
||||||
"""Ensure every key in QUERIES has a corresponding test."""
|
"""Ensure every key in QUERIES has a corresponding test."""
|
||||||
from unraid_mcp.tools.info import QUERIES
|
from unraid_mcp.tools.info import QUERIES
|
||||||
@@ -156,7 +150,7 @@ class TestInfoQueries:
|
|||||||
"overview", "array", "network", "registration", "connect",
|
"overview", "array", "network", "registration", "connect",
|
||||||
"variables", "metrics", "services", "display", "config",
|
"variables", "metrics", "services", "display", "config",
|
||||||
"online", "owner", "settings", "server", "servers",
|
"online", "owner", "settings", "server", "servers",
|
||||||
"flash", "ups_devices", "ups_device", "ups_config",
|
"flash", "ups_devices", "ups_device",
|
||||||
}
|
}
|
||||||
assert set(QUERIES.keys()) == expected_actions
|
assert set(QUERIES.keys()) == expected_actions
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ from .config.settings import (
|
|||||||
VERSION,
|
VERSION,
|
||||||
)
|
)
|
||||||
from .subscriptions.resources import register_subscription_resources
|
from .subscriptions.resources import register_subscription_resources
|
||||||
from .tools.array import register_array_tool
|
|
||||||
from .tools.docker import register_docker_tool
|
from .tools.docker import register_docker_tool
|
||||||
from .tools.health import register_health_tool
|
from .tools.health import register_health_tool
|
||||||
from .tools.info import register_info_tool
|
from .tools.info import register_info_tool
|
||||||
@@ -51,7 +50,6 @@ def register_all_modules() -> None:
|
|||||||
# Register all consolidated tools
|
# Register all consolidated tools
|
||||||
registrars = [
|
registrars = [
|
||||||
register_info_tool,
|
register_info_tool,
|
||||||
register_array_tool,
|
|
||||||
register_storage_tool,
|
register_storage_tool,
|
||||||
register_docker_tool,
|
register_docker_tool,
|
||||||
register_vm_tool,
|
register_vm_tool,
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ QUERIES: dict[str, str] = {
|
|||||||
""",
|
""",
|
||||||
"services": """
|
"services": """
|
||||||
query GetServices {
|
query GetServices {
|
||||||
services { name online uptime }
|
services { name online uptime { timestamp } }
|
||||||
}
|
}
|
||||||
""",
|
""",
|
||||||
"display": """
|
"display": """
|
||||||
@@ -103,7 +103,7 @@ QUERIES: dict[str, str] = {
|
|||||||
""",
|
""",
|
||||||
"owner": """
|
"owner": """
|
||||||
query GetOwner {
|
query GetOwner {
|
||||||
owner { username avatar url }
|
owner { username avatar }
|
||||||
}
|
}
|
||||||
""",
|
""",
|
||||||
"settings": """
|
"settings": """
|
||||||
@@ -115,7 +115,6 @@ QUERIES: dict[str, str] = {
|
|||||||
query GetServer {
|
query GetServer {
|
||||||
info {
|
info {
|
||||||
os { hostname uptime }
|
os { hostname uptime }
|
||||||
versions { unraid }
|
|
||||||
machineId time
|
machineId time
|
||||||
}
|
}
|
||||||
array { state }
|
array { state }
|
||||||
@@ -124,27 +123,22 @@ QUERIES: dict[str, str] = {
|
|||||||
""",
|
""",
|
||||||
"servers": """
|
"servers": """
|
||||||
query GetServers {
|
query GetServers {
|
||||||
servers { id name status description ip port }
|
servers { id name status lanip wanip }
|
||||||
}
|
}
|
||||||
""",
|
""",
|
||||||
"flash": """
|
"flash": """
|
||||||
query GetFlash {
|
query GetFlash {
|
||||||
flash { id guid product vendor size }
|
flash { id guid product vendor }
|
||||||
}
|
}
|
||||||
""",
|
""",
|
||||||
"ups_devices": """
|
"ups_devices": """
|
||||||
query GetUpsDevices {
|
query GetUpsDevices {
|
||||||
upsDevices { id model status runtime charge load }
|
upsDevices { id model status name battery { chargeLevel estimatedRuntime health } }
|
||||||
}
|
}
|
||||||
""",
|
""",
|
||||||
"ups_device": """
|
"ups_device": """
|
||||||
query GetUpsDevice($id: PrefixedID!) {
|
query GetUpsDevice($id: PrefixedID!) {
|
||||||
upsDeviceById(id: $id) { id model status runtime charge load voltage frequency temperature }
|
upsDeviceById(id: $id) { id model status name battery { chargeLevel estimatedRuntime health } power {loadPercentage inputVoltage outputVoltage } }
|
||||||
}
|
|
||||||
""",
|
|
||||||
"ups_config": """
|
|
||||||
query GetUpsConfig {
|
|
||||||
upsConfiguration { enabled mode cable driver port }
|
|
||||||
}
|
}
|
||||||
""",
|
""",
|
||||||
}
|
}
|
||||||
@@ -167,7 +161,6 @@ INFO_ACTIONS = Literal[
|
|||||||
"flash",
|
"flash",
|
||||||
"ups_devices",
|
"ups_devices",
|
||||||
"ups_device",
|
"ups_device",
|
||||||
"ups_config",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
assert set(QUERIES.keys()) == set(INFO_ACTIONS.__args__), (
|
assert set(QUERIES.keys()) == set(INFO_ACTIONS.__args__), (
|
||||||
@@ -334,7 +327,6 @@ def register_info_tool(mcp: FastMCP) -> None:
|
|||||||
flash - Flash drive info
|
flash - Flash drive info
|
||||||
ups_devices - List UPS devices
|
ups_devices - List UPS devices
|
||||||
ups_device - Single UPS device (requires device_id)
|
ups_device - Single UPS device (requires device_id)
|
||||||
ups_config - UPS configuration
|
|
||||||
"""
|
"""
|
||||||
if action not in QUERIES:
|
if action not in QUERIES:
|
||||||
raise ToolError(f"Invalid action '{action}'. Must be one of: {list(QUERIES.keys())}")
|
raise ToolError(f"Invalid action '{action}'. Must be one of: {list(QUERIES.keys())}")
|
||||||
@@ -358,7 +350,6 @@ def register_info_tool(mcp: FastMCP) -> None:
|
|||||||
"owner": "owner",
|
"owner": "owner",
|
||||||
"flash": "flash",
|
"flash": "flash",
|
||||||
"ups_device": "upsDeviceById",
|
"ups_device": "upsDeviceById",
|
||||||
"ups_config": "upsConfiguration",
|
|
||||||
}
|
}
|
||||||
# List-wrapped actions: action -> (GraphQL response key, output key)
|
# List-wrapped actions: action -> (GraphQL response key, output key)
|
||||||
list_actions: dict[str, tuple[str, str]] = {
|
list_actions: dict[str, tuple[str, str]] = {
|
||||||
|
|||||||
@@ -16,12 +16,12 @@ from ..core.exceptions import ToolError
|
|||||||
QUERIES: dict[str, str] = {
|
QUERIES: dict[str, str] = {
|
||||||
"list": """
|
"list": """
|
||||||
query ListApiKeys {
|
query ListApiKeys {
|
||||||
apiKeys { id name roles permissions { resource actions } createdAt lastUsed }
|
apiKeys { id name roles permissions { resource actions } createdAt }
|
||||||
}
|
}
|
||||||
""",
|
""",
|
||||||
"get": """
|
"get": """
|
||||||
query GetApiKey($id: PrefixedID!) {
|
query GetApiKey($id: PrefixedID!) {
|
||||||
apiKey(id: $id) { id name roles permissions { resource actions } createdAt lastUsed }
|
apiKey(id: $id) { id name roles permissions { resource actions } createdAt }
|
||||||
}
|
}
|
||||||
""",
|
""",
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user