- bd init: Dolt-backed issue tracker, prefix unraid-mcp-<hash> - .lavra/config/project-setup.md: python stack, 4 review agents - .lavra/config/codebase-profile.md: stack/arch/conventions profile - .gitignore: add lavra session-state and beads entries - CLAUDE.md: beads workflow integration block Co-Authored-By: Claude <noreply@anthropic.com>
3.9 KiB
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/unraidbin 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).