# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview **MCP Hub** — a Python MCP (Model Context Protocol) server that manages multiple self-hosted services through a unified plugin architecture. Supports 9 plugin types (WordPress, WooCommerce, WordPress Advanced, Gitea, n8n, Supabase, OpenPanel, Appwrite, Directus) with 565 tools total. The tool count stays constant regardless of how many sites are configured. ## Quick Setup ```bash cp env.example .env # Copy and fill in credentials pip install -e ".[dev]" # Install with dev deps python server.py # Run (stdio) or: python server.py --transport streamable-http --port 8000 # Run (HTTP) ``` ## Build & Development Commands ```bash # Install with dev dependencies pip install -e ".[dev]" # Run server (stdio transport for Claude Desktop) python server.py # Run server (HTTP transport for testing) python server.py --transport streamable-http --port 8000 # Run all tests pytest # Run single test file pytest tests/test_api_keys.py # Run by marker (unit, integration, security, slow) pytest -m unit pytest -m "not slow" # Tests with coverage pytest --cov --cov-report=html # Format code black . # Lint ruff check . ruff check --fix . # Type check mypy . # Docker build and run docker build -t mcphub . docker-compose up -d ``` ## Code Quality Configuration All configured in `pyproject.toml`: - **Black**: line-length=100, target py311 - **Ruff**: strict rules (E, W, F, I, N, D, UP, B, C4, SIM, TCH, PTH), Google-style docstrings - **mypy**: Python 3.11, strict equality, check_untyped_defs=true - **pytest**: asyncio_mode="auto", testpaths=["tests"], markers: slow, integration, unit, security ## Architecture ### Root Directory Overview ``` ├── server.py # Primary entry point ├── server_multi.py # Alternative multi-endpoint server ├── core/ # Layer 1: Core system modules ├── plugins/ # Layer 2: Plugin system (9 plugins) ├── core/templates/ # Jinja2 templates (dashboard + OAuth) ├── tests/ # Organized test suite ├── scripts/ # Setup & deployment scripts ├── wordpress-plugin/ # Companion WP plugins (PHP) ├── docs/ # Extensive documentation ├── pyproject.toml # All tool configs (black, ruff, mypy, pytest) ├── docker-compose.yaml # Docker composition └── env.example # Environment variable template ``` ### Three-Layer Clean Architecture ("Option B") ``` Layer 1: Core System (core/) — Auth, site discovery, tool registry, health, rate limiting Layer 2: Plugin System (plugins/) — 9 plugin types, each with handlers + schemas Layer 3: API & Web UI (server.py + core/dashboard/) — FastMCP server, Starlette routes, dashboard ``` ### Entry Points - **`server.py`** (~3500 lines) — Primary entry point. Handles FastMCP server, Starlette routes, middleware, plugins. - **`server_multi.py`** — Alternative multi-endpoint server (legacy, predates unified `server.py` endpoints). ### Multi-Endpoint Architecture ``` /mcp → Admin (all tools, Master API Key required) /system/mcp → System tools only /{plugin_type}/mcp → Plugin-specific tools (wordpress, gitea, n8n, etc.) /project/{alias_or_id}/mcp → Per-project endpoint (auto-injects site parameter) ``` Implemented in `core/endpoints/` — EndpointConfig, MCPEndpointFactory, EndpointRegistry. ### Plugin System All plugins extend `BasePlugin` (in `plugins/base.py`). Registration happens in `plugins/__init__.py` via `PluginRegistry`. Each plugin follows this structure: ``` plugins/{name}/ ├── plugin.py # Main class extending BasePlugin ├── client.py # REST API client for the service ├── handlers/ # Feature-specific handlers (posts.py, orders.py, etc.) └── schemas/ # Pydantic models for validation ``` **Registered plugins**: wordpress, woocommerce, wordpress_advanced, gitea, n8n, supabase, openpanel, appwrite, directus **Plugin visibility** (Track F.1): Public users only see plugins listed in `ENABLED_PLUGINS` env var (default: `wordpress,woocommerce,supabase`). Admin sees all. Controlled by `core/plugin_visibility.py`. ### Tool Generation Tools are dynamically generated at startup from plugin specifications: 1. `ToolGenerator` creates unified tools with a `site` parameter injected 2. Tools are registered in `ToolRegistry` and exposed via FastMCP Unified tool pattern: `wordpress_create_post(site="myblog", title="Hello")` — the `site` parameter accepts either a site_id or alias. ### Site Configuration Sites are managed via the web dashboard and stored in SQLite (DB-based). User sites are encrypted with AES-256-GCM and accessed via `core/site_api.py` + `core/database.py`. `SiteManager` (`core/site_manager.py`) provides registration and lookup infrastructure for tool generation. ### Key Core Modules | Module | Purpose | |--------|---------| | `core/auth.py` | Master API key validation, request authentication | | `core/api_keys.py` | Per-project API keys with scopes (read/write/admin) | | `core/site_manager.py` | Type-safe site config registration and lookup | | `core/tool_registry.py` | Central tool definitions and lookup | | `core/tool_generator.py` | Dynamic unified tool creation with site injection | | `core/health.py` | Health monitoring, metrics, alerts | | `core/rate_limiter.py` | Token bucket rate limiting (60/min, 1000/hr, 10k/day) | | `core/audit_log.py` | GDPR-compliant JSON audit logging | | `core/oauth/` | OAuth 2.1 with PKCE (RFC 8414, 7591, 7636) | | `core/dashboard/routes.py` | Web UI dashboard (login, projects, API keys, health, audit) | | `core/endpoints/` | Multi-endpoint architecture (factory, registry, config) | | `core/plugin_visibility.py` | Plugin enable/disable for public vs admin users | | `core/user_auth.py` | OAuth Social Login (GitHub + Google) | | `core/user_endpoints.py` | Per-user MCP endpoints (`/u/{user_id}/{alias}/mcp`) | | `core/site_api.py` | User site CRUD, connection testing, credential encryption | | `core/user_keys.py` | User API key management (bcrypt, `mhu_` prefix) | | `core/database.py` | SQLite backend (aiosqlite, WAL mode, migrations) | | `core/encryption.py` | AES-256-GCM credential encryption | ### User System (Track E) OAuth Social Login (GitHub + Google) via `core/user_auth.py`. Users register, add sites, get personal MCP endpoints at `/u/{user_id}/{alias}/mcp`. Per-user API keys with `mhu_` prefix (bcrypt-hashed). Credentials encrypted with AES-256-GCM in SQLite. ### Dashboard Web UI at the server root, built with Starlette + Jinja2 + HTMX + Tailwind CSS. Supports EN/FA i18n (`core/i18n.py`). **Admin pages**: Login, Home, Projects, API Keys, OAuth Clients, Audit Logs, Health, Settings. **User pages**: Login (OAuth), Home, My Sites (list/add/edit/test/delete), Connect (API keys + config snippets + OAuth clients), Profile. ### Legacy Modules (Deprecated) `core/project_manager.py` (retained for HealthMonitor compatibility), `core/site_registry.py`, `core/unified_tools.py` — kept for backward compatibility. New code should use `SiteManager`, `ToolRegistry`, and `ToolGenerator` instead. ## Commit Style ``` (): ``` Types: `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore` ## Live Instances - **Platform**: `mcp.example.com` — Live MCP Hub with OAuth login - **Blog**: `blog.example.com` — WordPress test site + project blog - **Deployment**: Coolify / Docker Compose, port 8000 ## Current Development (Track F) v4 development cycle with 15 phases. See `docs/ROADMAP.md` (Track F) and `.claude/plans/structured-popping-adleman.md` for full plan. **Active plugins for public users**: WordPress, WooCommerce, Supabase, OpenPanel (configurable via `ENABLED_PLUGINS` env var) ## Gotchas - Test files exist in both `tests/` (proper) and root directory (legacy `test_*.py`). Run `pytest tests/` for organized tests only. - `server_multi.py` is the alternative multi-endpoint entry point; `server.py` is the primary - `wordpress-plugin/` contains companion WP plugins (openpanel, airano-mcp-seo-bridge) — these are PHP, not Python - `env.example` has "FUTURE" labels for Supabase/Gitea but both are fully implemented - 4 plugins are tested for public use: WordPress, WooCommerce, Supabase, OpenPanel. Others are admin-only or disabled. - OAuth Clients (Client ID/Secret) are for MCP endpoint auth, NOT the same as GitHub/Google dashboard login - All sites stored in SQLite (`core/database.py`), managed via web dashboard - Dashboard templates live in `core/templates/` (included in pip package as `package_data`) - `ruff` config uses top-level `select` key in pyproject.toml (not `[tool.ruff.lint]` nested format) - The `scripts/` directory has platform-specific setup scripts: `setup.sh` (Linux/Mac), `setup.ps1` (Windows) ## Deployment Notes - **Coolify**: Docker Compose build pack, port 8000, health check `GET /health` - Must listen on `0.0.0.0` (not localhost) - Docker socket mount required for WP-CLI tools: `/var/run/docker.sock:/var/run/docker.sock:ro` - Persistent volumes: `mcp-data` (API keys, OAuth), `mcp-logs` (audit, health) - Required env vars: `MASTER_API_KEY`, `OAUTH_JWT_SECRET_KEY`, `OAUTH_BASE_URL` - OAuth env vars: `GITHUB_CLIENT_ID`, `GITHUB_CLIENT_SECRET`, `GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET`, `PUBLIC_URL` - User limits: `MAX_SITES_PER_USER=10`, `USER_RATE_LIMIT_PER_MIN=30`, `USER_RATE_LIMIT_PER_HR=500` - Plugin visibility: `ENABLED_PLUGINS=wordpress,woocommerce,supabase,openpanel` (default)