# Codebase Profile Generated by /project-setup on 2026-03-27 ## Stack & Integrations **Language & Runtime** - Python 3.12+ (min requirement), supports 3.13 - Build system: Hatchling 1.25.0+, package manager: uv **Core Frameworks** - FastMCP 3.0.0+: MCP server framework - FastAPI 0.115.0+, Uvicorn 0.35.0+: ASGI layer - Pydantic: validation/serialization **API & Communication** - httpx 0.28.1+: async HTTP client for GraphQL queries - websockets 15.0.1+: WebSocket client for real-time subscriptions - graphql-core 3.2.0+: GraphQL query validation (dev dep) **Configuration** - python-dotenv 1.1.1+: env var management - rich 14.1.0+: terminal output/logging **Testing** - pytest 8.4.2+, pytest-asyncio 1.2.0+, pytest-cov 7.0.0+ - respx 0.22.0+: httpx request mocking - hypothesis 6.151.9+: property-based testing **Quality** - ruff 0.12.8+: lint/format; ty 0.0.15+: type checking **External Dependencies** - Unraid GraphQL API (primary backend via httpx) - WebSocket subscriptions to Unraid server (persistent connections) - Supports custom CA certs (UNRAID_VERIFY_SSL) **Entry Points** - CLI: `unraid-mcp-server` / `unraid` bin scripts - 1 primary MCP tool: `unraid` (15 domains, ~108 subactions) - 2 diagnostic tools: `diagnose_subscriptions`, `test_subscription_query` - 10 live snapshot MCP resources under `unraid://` namespace ## Architecture & Structure ``` unraid_mcp/ ├── core/ # GraphQL client, exceptions, types, guards ├── config/ # Settings, logging, env validation ├── tools/ # Consolidated unraid tool (15 action domains) ├── subscriptions/ # WebSocket manager, resources, diagnostics ├── main.py # Entry point with shutdown cleanup └── server.py # FastMCP init + 5-layer middleware chain ``` **server.py**: FastMCP init with middleware: logging → error_handling → rate_limiting → response_limiting → caching. Registers all tools/resources at import. **tools/unraid.py**: Single consolidated tool (~1900 lines). 15 actions dispatch to domain handlers. Destructive actions require `confirm=True`. **core/client.py**: GraphQL HTTP client (httpx-based) with sensitive key redaction, request/response logging, timeout management, credentials elicitation. **config/settings.py**: Env var parsing for API URL, credentials, host/port, SSL, timeouts, log level, transport. **subscriptions/manager.py**: Singleton SubscriptionManager for WebSocket lifecycle and real-time streaming. **Data Flow**: `unraid(action, subaction)` → domain handler → GraphQL query → httpx → Unraid API → response **Patterns**: - Consolidated single-tool MCP (action+subaction multiplexing) - Singleton SubscriptionManager for WebSocket lifecycle - Middleware chain (logging wraps all; caching disabled for mutations) - Elicitation flow for first-run credential setup ## Conventions & Testing **Test Framework**: pytest with asyncio auto mode; `make_tool_fn` helper in conftest for tool extraction from FastMCP. **Test Layout**: - Root: domain unit tests (test_array.py, test_docker.py, etc.) - tests/safety/: destructive action guard audits - tests/schema/: GraphQL query validation - tests/http_layer/: respx-based HTTP mocking - tests/contract/: response structure contracts - tests/property/: hypothesis property-based tests - tests/integration/: WebSocket subscription lifecycle (slow, mock WS) **Key Patching Rule**: Patch at `unraid_mcp.tools.unraid.make_graphql_request` (tool module level), NOT core module. **Naming**: `Test{Feature}` classes, async `test_*` methods, `_DOMAIN_QUERIES` dicts, `register_{domain}_tool()` functions. **CI**: uv-based: lint (ruff) → typecheck (ty) → test (pytest) → version-sync → audit. Coverage 80% with branch coverage. Version sync enforces pyproject.toml ↔ .claude-plugin/plugin.json consistency. **Ruff config**: line length 100, ignores D1xx/D2xx/D7xx (docstring), S101 (assert in tests).