mirror of
https://github.com/jmagar/unraid-mcp.git
synced 2026-03-23 04:29:17 -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",
|
||||
"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": {
|
||||
"name": "jmagar",
|
||||
"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
|
||||
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]
|
||||
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"
|
||||
readme = "README.md"
|
||||
license = {file = "LICENSE"}
|
||||
|
||||
@@ -85,6 +85,10 @@ mcp = FastMCP(
|
||||
# Note: SubscriptionManager singleton is defined in subscriptions/manager.py
|
||||
# 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:
|
||||
"""Register all tools and resources with the MCP instance."""
|
||||
@@ -103,6 +107,9 @@ def register_all_modules() -> None:
|
||||
raise
|
||||
|
||||
|
||||
register_all_modules()
|
||||
|
||||
|
||||
def run_server() -> None:
|
||||
"""Run the MCP server with the configured transport."""
|
||||
# Validate required configuration before anything else
|
||||
@@ -125,9 +132,6 @@ def run_server() -> None:
|
||||
"Only use this in trusted networks or for development."
|
||||
)
|
||||
|
||||
# Register all modules
|
||||
register_all_modules()
|
||||
|
||||
logger.info(
|
||||
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:
|
||||
"""Register the single `unraid` tool with the FastMCP instance."""
|
||||
|
||||
@mcp.tool()
|
||||
@mcp.tool(timeout=120)
|
||||
async def unraid(
|
||||
action: UNRAID_ACTIONS,
|
||||
subaction: str,
|
||||
|
||||
Reference in New Issue
Block a user