mirror of
https://github.com/jmagar/unraid-mcp.git
synced 2026-03-23 12:39:24 -07:00
fix: address 18 PR review comments (threads 1-18)
Threads 1, 2, 3 — test hygiene:
- Move elicit_and_configure/elicit_reset_confirmation to module-level imports
in unraid.py so tests can patch at unraid_mcp.tools.unraid.* (thread 2)
- Add return type annotations to _make_tool() in test_customization.py (thread 1)
- Replace unused _mock_ensure_started fixture params with @usefixtures (thread 3)
Thread 4 — remove dead 'connect' subaction from _SYSTEM_QUERIES; the subaction
was always rejected with a ToolError, creating an inconsistent contract.
Thread 5 — centralize two inline "query { online }" strings by reusing
_SYSTEM_QUERIES["online"]; add _DOCKER_QUERIES["_resolve"] for container-name
resolution instead of an inline query literal.
Threads 14, 15, 16, 17, 18 — test improvements:
- test-tools.sh: reword header to "broad non-destructive smoke coverage" (t14)
- test-tools.sh: add _json_payload() helper using jq --arg for safe JSON
construction; replace all printf-based payloads (thread 15)
- test_input_validation.py: add return type annotations to _make_tool and all
nested _run_test coroutines (thread 16)
- test_query_validation.py: extract _all_domain_dicts() shared helper to
eliminate the duplicate 22-item registry (thread 17)
- test_query_validation.py: tighten regression threshold from 50 → 90 (thread 18)
This commit is contained in:
@@ -7,6 +7,11 @@ separate modules for configuration, core functionality, subscriptions, and tools
|
||||
import sys
|
||||
|
||||
from fastmcp import FastMCP
|
||||
from fastmcp.server.middleware.caching import CallToolSettings, ResponseCachingMiddleware
|
||||
from fastmcp.server.middleware.error_handling import ErrorHandlingMiddleware
|
||||
from fastmcp.server.middleware.logging import LoggingMiddleware
|
||||
from fastmcp.server.middleware.rate_limiting import SlidingWindowRateLimitingMiddleware
|
||||
from fastmcp.server.middleware.response_limiting import ResponseLimitingMiddleware
|
||||
|
||||
from .config.logging import logger
|
||||
from .config.settings import (
|
||||
@@ -22,11 +27,59 @@ from .subscriptions.resources import register_subscription_resources
|
||||
from .tools.unraid import register_unraid_tool
|
||||
|
||||
|
||||
# Middleware chain order matters — each layer wraps everything inside it:
|
||||
# logging → error_handling → rate_limiter → response_limiter → cache → tool
|
||||
|
||||
# 1. Log every tools/call and resources/read: method, duration, errors.
|
||||
# Outermost so it captures errors after they've been converted by error_handling.
|
||||
_logging_middleware = LoggingMiddleware(
|
||||
logger=logger,
|
||||
methods=["tools/call", "resources/read"],
|
||||
)
|
||||
|
||||
# 2. Catch any unhandled exceptions and convert to proper MCP errors.
|
||||
# Tracks error_counts per (exception_type:method) for health diagnose.
|
||||
error_middleware = ErrorHandlingMiddleware(
|
||||
logger=logger,
|
||||
include_traceback=True,
|
||||
)
|
||||
|
||||
# 3. Unraid API rate limit: 100 requests per 10 seconds.
|
||||
# Use a sliding window that stays comfortably under that cap.
|
||||
_rate_limiter = SlidingWindowRateLimitingMiddleware(max_requests=90, window_minutes=1)
|
||||
|
||||
# 4. Cap tool responses at 512 KB to protect the client context window.
|
||||
# Oversized responses are truncated with a clear suffix rather than erroring.
|
||||
_response_limiter = ResponseLimitingMiddleware(max_size=512_000)
|
||||
|
||||
# 5. Cache tool calls in-memory (MemoryStore default — no extra deps).
|
||||
# Short 30 s TTL absorbs burst duplicate requests while keeping data fresh.
|
||||
# Destructive calls won't hit the cache in practice (unique confirm=True + IDs).
|
||||
cache_middleware = ResponseCachingMiddleware(
|
||||
call_tool_settings=CallToolSettings(
|
||||
ttl=30,
|
||||
included_tools=["unraid"],
|
||||
),
|
||||
# Disable caching for list/resource/prompt — those are cheap.
|
||||
list_tools_settings={"enabled": False},
|
||||
list_resources_settings={"enabled": False},
|
||||
list_prompts_settings={"enabled": False},
|
||||
read_resource_settings={"enabled": False},
|
||||
get_prompt_settings={"enabled": False},
|
||||
)
|
||||
|
||||
# Initialize FastMCP instance
|
||||
mcp = FastMCP(
|
||||
name="Unraid MCP Server",
|
||||
instructions="Provides tools to interact with an Unraid server's GraphQL API.",
|
||||
version=VERSION,
|
||||
middleware=[
|
||||
_logging_middleware,
|
||||
error_middleware,
|
||||
_rate_limiter,
|
||||
_response_limiter,
|
||||
cache_middleware,
|
||||
],
|
||||
)
|
||||
|
||||
# Note: SubscriptionManager singleton is defined in subscriptions/manager.py
|
||||
|
||||
Reference in New Issue
Block a user