mirror of
https://github.com/jmagar/unraid-mcp.git
synced 2026-03-23 12:39:24 -07:00
feat(dx): add fastmcp.json configs, module-level tool registration, tool timeout
- Add fastmcp.http.json and fastmcp.stdio.json declarative server configs for streamable-http (:6970) and stdio transports respectively - Move register_all_modules() to module level in server.py so `fastmcp run server.py --reload` discovers the fully-wired mcp object without going through run_server() — tools registered exactly once - Add timeout=120 to @mcp.tool() decorator as a global safety net; any hung subaction returns a clean MCP error instead of hanging forever - Document fastmcp run --reload, fastmcp list, fastmcp call in README - Bump version 1.0.1 → 1.1.0 Co-authored-by: Claude <claude@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "unraid",
|
"name": "unraid",
|
||||||
"description": "Query and monitor Unraid servers via GraphQL API - array status, disk health, containers, VMs, system monitoring",
|
"description": "Query and monitor Unraid servers via GraphQL API - array status, disk health, containers, VMs, system monitoring",
|
||||||
"version": "1.0.1",
|
"version": "1.1.0",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "jmagar",
|
"name": "jmagar",
|
||||||
"email": "jmagar@users.noreply.github.com"
|
"email": "jmagar@users.noreply.github.com"
|
||||||
|
|||||||
22
README.md
22
README.md
@@ -399,6 +399,28 @@ uv run unraid-mcp-server
|
|||||||
|
|
||||||
# Or run via module directly
|
# Or run via module directly
|
||||||
uv run -m unraid_mcp.main
|
uv run -m unraid_mcp.main
|
||||||
|
|
||||||
|
# Hot-reload dev server (restarts on file changes)
|
||||||
|
fastmcp run fastmcp.http.json --reload
|
||||||
|
|
||||||
|
# Run via named config files
|
||||||
|
fastmcp run fastmcp.http.json # streamable-http on :6970
|
||||||
|
fastmcp run fastmcp.stdio.json # stdio transport
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ad-hoc Tool Testing (fastmcp CLI)
|
||||||
|
```bash
|
||||||
|
# Introspect the running server
|
||||||
|
fastmcp list http://localhost:6970/mcp
|
||||||
|
fastmcp list http://localhost:6970/mcp --input-schema
|
||||||
|
|
||||||
|
# Call a tool directly (HTTP)
|
||||||
|
fastmcp call http://localhost:6970/mcp unraid action=health subaction=check
|
||||||
|
fastmcp call http://localhost:6970/mcp unraid action=docker subaction=list
|
||||||
|
|
||||||
|
# Call without a running server (stdio config)
|
||||||
|
fastmcp list fastmcp.stdio.json
|
||||||
|
fastmcp call fastmcp.stdio.json unraid action=health subaction=check
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
23
fastmcp.http.json
Normal file
23
fastmcp.http.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://gofastmcp.com/public/schemas/fastmcp.json/v1.json",
|
||||||
|
"source": {
|
||||||
|
"path": "unraid_mcp/server.py",
|
||||||
|
"entrypoint": "mcp"
|
||||||
|
},
|
||||||
|
"environment": {
|
||||||
|
"type": "uv",
|
||||||
|
"python": "3.12",
|
||||||
|
"editable": ["."]
|
||||||
|
},
|
||||||
|
"deployment": {
|
||||||
|
"transport": "http",
|
||||||
|
"host": "0.0.0.0",
|
||||||
|
"port": 6970,
|
||||||
|
"path": "/mcp",
|
||||||
|
"log_level": "INFO",
|
||||||
|
"env": {
|
||||||
|
"UNRAID_API_URL": "${UNRAID_API_URL}",
|
||||||
|
"UNRAID_API_KEY": "${UNRAID_API_KEY}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
20
fastmcp.stdio.json
Normal file
20
fastmcp.stdio.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://gofastmcp.com/public/schemas/fastmcp.json/v1.json",
|
||||||
|
"source": {
|
||||||
|
"path": "unraid_mcp/server.py",
|
||||||
|
"entrypoint": "mcp"
|
||||||
|
},
|
||||||
|
"environment": {
|
||||||
|
"type": "uv",
|
||||||
|
"python": "3.12",
|
||||||
|
"editable": ["."]
|
||||||
|
},
|
||||||
|
"deployment": {
|
||||||
|
"transport": "stdio",
|
||||||
|
"log_level": "INFO",
|
||||||
|
"env": {
|
||||||
|
"UNRAID_API_URL": "${UNRAID_API_URL}",
|
||||||
|
"UNRAID_API_KEY": "${UNRAID_API_KEY}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@ build-backend = "hatchling.build"
|
|||||||
# ============================================================================
|
# ============================================================================
|
||||||
[project]
|
[project]
|
||||||
name = "unraid-mcp"
|
name = "unraid-mcp"
|
||||||
version = "1.0.1"
|
version = "1.1.0"
|
||||||
description = "MCP Server for Unraid API - provides tools to interact with an Unraid server's GraphQL API"
|
description = "MCP Server for Unraid API - provides tools to interact with an Unraid server's GraphQL API"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
license = {file = "LICENSE"}
|
license = {file = "LICENSE"}
|
||||||
|
|||||||
@@ -85,6 +85,10 @@ mcp = FastMCP(
|
|||||||
# Note: SubscriptionManager singleton is defined in subscriptions/manager.py
|
# Note: SubscriptionManager singleton is defined in subscriptions/manager.py
|
||||||
# and imported by resources.py - no duplicate instance needed here
|
# and imported by resources.py - no duplicate instance needed here
|
||||||
|
|
||||||
|
# Register all modules at import time so `fastmcp run server.py --reload` can
|
||||||
|
# discover the fully-configured `mcp` object without going through run_server().
|
||||||
|
# run_server() no longer calls this — tools are registered exactly once here.
|
||||||
|
|
||||||
|
|
||||||
def register_all_modules() -> None:
|
def register_all_modules() -> None:
|
||||||
"""Register all tools and resources with the MCP instance."""
|
"""Register all tools and resources with the MCP instance."""
|
||||||
@@ -103,6 +107,9 @@ def register_all_modules() -> None:
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
register_all_modules()
|
||||||
|
|
||||||
|
|
||||||
def run_server() -> None:
|
def run_server() -> None:
|
||||||
"""Run the MCP server with the configured transport."""
|
"""Run the MCP server with the configured transport."""
|
||||||
# Validate required configuration before anything else
|
# Validate required configuration before anything else
|
||||||
@@ -125,9 +132,6 @@ def run_server() -> None:
|
|||||||
"Only use this in trusted networks or for development."
|
"Only use this in trusted networks or for development."
|
||||||
)
|
)
|
||||||
|
|
||||||
# Register all modules
|
|
||||||
register_all_modules()
|
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Starting Unraid MCP Server on {UNRAID_MCP_HOST}:{UNRAID_MCP_PORT} using {UNRAID_MCP_TRANSPORT} transport..."
|
f"Starting Unraid MCP Server on {UNRAID_MCP_HOST}:{UNRAID_MCP_PORT} using {UNRAID_MCP_TRANSPORT} transport..."
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1722,7 +1722,7 @@ UNRAID_ACTIONS = Literal[
|
|||||||
def register_unraid_tool(mcp: FastMCP) -> None:
|
def register_unraid_tool(mcp: FastMCP) -> None:
|
||||||
"""Register the single `unraid` tool with the FastMCP instance."""
|
"""Register the single `unraid` tool with the FastMCP instance."""
|
||||||
|
|
||||||
@mcp.tool()
|
@mcp.tool(timeout=120)
|
||||||
async def unraid(
|
async def unraid(
|
||||||
action: UNRAID_ACTIONS,
|
action: UNRAID_ACTIONS,
|
||||||
subaction: str,
|
subaction: str,
|
||||||
|
|||||||
Reference in New Issue
Block a user