Files
unraid-mcp/.lavra/config/codebase-profile.md
Jacob Magar 207b68cd8c chore: initialize beads + lavra project config (v1.1.5)
- 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>
2026-03-27 21:30:12 -04:00

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 / 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).