Files
mcphub/CLAUDE.md
airano-ir 43fd2201a0 feat(v3.13.0): settings live DB reads, remove Directus/Appwrite, admin stats
Settings fixes:
- MAX_SITES_PER_USER, USER_RATE_LIMIT_PER_MIN/HR now read from DB settings
  table (DB > ENV > default), so dashboard/settings changes apply without
  restart. Sync cache refreshed on every save or delete.
- /api/me reports the live DB value for max_sites_per_user.

Admin improvements:
- Admin users bypass per-user rate limiting entirely (role=admin or ADMIN_EMAILS).
- Admin Overview now shows platform stats: registered users, new users (7d),
  total user sites, available tools.

Plugin cleanup:
- Appwrite and Directus plugins removed from the active registry (8 plugins
  now: WordPress, WooCommerce, WordPress Specialist, Gitea, n8n, Supabase,
  OpenPanel, Coolify). Plugin code is retained for future re-enabling.
- Settings page plugin visibility list updated to match.

Mobile onboarding:
- Stepper steps on narrow viewports stack vertically with correct full border
  and rounded corners on each step.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-20 23:33:20 +02:00

10 KiB

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 8 active plugin types (WordPress, WooCommerce, WordPress Specialist, Gitea, n8n, Supabase, OpenPanel, Coolify). Total tool count varies with which plugins are enabled and grows as new plugins are added; per-plugin counts are surfaced in the dashboard. The exposed count for a given user/endpoint stays constant regardless of how many sites of the same type are configured.

Quick Setup

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

# 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

Frontend (web/) — Track G

The redesigned dashboard SPA lives in web/ (Vite + React 18 + TypeScript). Build artifacts land in core/templates/static/dist/ and are served by Starlette under /static/dist/ and routed at /dashboard-v2/*. Legacy Jinja dashboard at /dashboard/* is unchanged during the coexistence window.

# Install JS deps (one-time)
cd web && npm install

# Dev server (proxies /api, /auth, /dashboard, /static to localhost:8000)
cd web && npm run dev

# Type-check and run unit tests
cd web && npm run typecheck
cd web && npm test

# Production build (writes hashed bundles into core/templates/static/dist)
cd web && npm run build

# SPA-support backend tests
pytest -m frontend

Logo: core/templates/static/logo.svg is the single source of truth and is copied verbatim into web/public/ during build. The React Logo component inlines the same path data and themes its fills via CSS vars.

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, frontend

Architecture

Root Directory Overview

├── server.py              # Primary entry point
├── core/                  # Layer 1: Core system modules
├── plugins/               # Layer 2: Plugin system (10 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/)   — 10 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.

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_specialist, gitea, n8n, supabase, openpanel, coolify

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.

Commit Style

<type>(<scope>): <description>

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, Gitea (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.
  • wordpress-plugin/ contains companion WP plugins (openpanel, airano-mcp-bridge) — these are PHP, not Python
  • env.example has "FUTURE" labels for Supabase/Gitea but both are fully implemented
  • 8 active plugins: WordPress, WooCommerce, WordPress Specialist, Supabase, OpenPanel, Gitea, n8n, Coolify. Appwrite/Directus code is retained in plugins/ but not registered (need review before re-enabling).
  • 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,gitea (default)