fix: correct tool count (596), default English dashboard, clean up stale references
- Tool count corrected: 589→596 (was missing 4 OAuth + 4 system config tools) - System tools: 17→24 (accurate count of @mcp.tool() functions) - Dashboard defaults to English; Farsi only via ?lang=fa query param - Updated across all files: README, CLAUDE.md, CONTRIBUTING, DOCKER_README, getting-started, CHANGELOG, endpoints config - Removed remaining Phase references from server.py startup log - Tests: 289 passing Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -30,7 +30,7 @@ After 2-month hiatus (Dec 2025 - Feb 2026), updated all dependencies and verifie
|
||||
- All 54 tests now pass (previously 5 were failing)
|
||||
|
||||
#### Verified
|
||||
- All 589 tools generate correctly
|
||||
- All 596 tools generate correctly
|
||||
- Middleware API stable (Middleware, MiddlewareContext, get_http_headers)
|
||||
- 30+ custom routes operational (dashboard + OAuth)
|
||||
- Multi-endpoint architecture functional
|
||||
|
||||
@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
||||
|
||||
## Project Overview
|
||||
|
||||
**MCP Hub** — a Python MCP (Model Context Protocol) server that manages multiple self-hosted projects through a unified plugin architecture. Supports 9 plugin types (WordPress, WooCommerce, WordPress Advanced, Gitea, n8n, Supabase, OpenPanel, Appwrite, Directus) with ~589 tools total. The tool count stays constant regardless of how many sites are configured.
|
||||
**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 596 tools total. The tool count stays constant regardless of how many sites are configured.
|
||||
|
||||
## Quick Setup
|
||||
|
||||
|
||||
@@ -119,8 +119,8 @@ Then register in `plugins/__init__.py` and add tests.
|
||||
```
|
||||
core/ # Core system (auth, site manager, tool registry, dashboard)
|
||||
plugins/ # Plugin system (9 plugins, each with handlers + schemas)
|
||||
templates/ # Jinja2 templates (dashboard + OAuth)
|
||||
tests/ # Test suite (289 tests)
|
||||
core/templates/ # Jinja2 templates (dashboard + OAuth)
|
||||
tests/ # Test suite (290 tests)
|
||||
scripts/ # Setup & deployment scripts
|
||||
docs/ # Documentation
|
||||
```
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
**The AI-native management hub for WordPress, WooCommerce, and self-hosted services.**
|
||||
|
||||
589 tools across 9 plugins. Connect your sites, stores, repos, and databases — manage them all through Claude, ChatGPT, Cursor, or any MCP client.
|
||||
596 tools across 9 plugins. Connect your sites, stores, repos, and databases — manage them all through Claude, ChatGPT, Cursor, or any MCP client.
|
||||
|
||||
## Quick Start
|
||||
|
||||
|
||||
12
README.md
12
README.md
@@ -11,7 +11,7 @@ Connect your sites, stores, repos, and databases — manage them all through Cla
|
||||
[](https://pypi.org/project/mcphub-server/)
|
||||
[](https://hub.docker.com/r/airano/mcphub)
|
||||
[]()
|
||||
[]()
|
||||
[]()
|
||||
[](https://github.com/airano-ir/mcphub/actions/workflows/ci.yml)
|
||||
|
||||
</div>
|
||||
@@ -46,7 +46,7 @@ MCP Hub is the first MCP server that lets you manage WordPress, WooCommerce, and
|
||||
|
||||
---
|
||||
|
||||
## 589 Tools Across 9 Plugins
|
||||
## 596 Tools Across 9 Plugins
|
||||
|
||||
| Plugin | Tools | What You Can Do |
|
||||
|--------|-------|-----------------|
|
||||
@@ -59,8 +59,8 @@ MCP Hub is the first MCP server that lets you manage WordPress, WooCommerce, and
|
||||
| **OpenPanel** | 73 | Events, funnels, profiles, dashboards, projects |
|
||||
| **Appwrite** | 100 | Databases, auth, storage, functions, teams, messaging |
|
||||
| **Directus** | 100 | Collections, items, users, files, flows, permissions |
|
||||
| **System** | 17 | Health monitoring, API keys, project discovery |
|
||||
| **Total** | **589** | Constant count — scales to unlimited sites |
|
||||
| **System** | 24 | Health monitoring, API keys, OAuth management, audit |
|
||||
| **Total** | **596** | Constant count — scales to unlimited sites |
|
||||
|
||||
---
|
||||
|
||||
@@ -224,8 +224,8 @@ MCP Hub supports **Open Dynamic Client Registration** (RFC 7591). ChatGPT can au
|
||||
## Architecture
|
||||
|
||||
```
|
||||
/mcp → Admin endpoint (all 589 tools)
|
||||
/system/mcp → System tools only (17 tools)
|
||||
/mcp → Admin endpoint (all 596 tools)
|
||||
/system/mcp → System tools only (24 tools)
|
||||
/wordpress/mcp → WordPress tools (67 tools)
|
||||
/woocommerce/mcp → WooCommerce tools (28 tools)
|
||||
/gitea/mcp → Gitea tools (56 tools)
|
||||
|
||||
@@ -157,15 +157,10 @@ DASHBOARD_TRANSLATIONS = {
|
||||
|
||||
|
||||
def detect_language(accept_language: str | None, query_lang: str | None = None) -> str:
|
||||
"""Detect language from Accept-Language header or query parameter."""
|
||||
"""Detect language from query parameter. Default is English."""
|
||||
if query_lang and query_lang in DASHBOARD_TRANSLATIONS:
|
||||
return query_lang
|
||||
|
||||
if accept_language:
|
||||
# Check for Persian/Farsi
|
||||
if "fa" in accept_language.lower() or "fa-ir" in accept_language.lower():
|
||||
return "fa"
|
||||
|
||||
return "en"
|
||||
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ ENDPOINT_CONFIGS = {
|
||||
allowed_scopes={"admin"},
|
||||
max_tools=400,
|
||||
),
|
||||
# System endpoint - system tools only (17 tools) - Phase X.3
|
||||
# System endpoint - system tools only (24 tools)
|
||||
# For API key management, OAuth, rate limiting without loading all plugins
|
||||
EndpointType.SYSTEM: EndpointConfig(
|
||||
path="/system",
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
<div class="mt-6 text-center" {% if lang == 'fa' %}dir="rtl"{% endif %}>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t.need_help }}
|
||||
<a href="https://github.com/airano-ir/coolify-mcp-hub" class="text-purple-600 dark:text-purple-400 hover:underline">{{ t.documentation }}</a>
|
||||
<a href="https://github.com/airano-ir/mcphub" class="text-purple-600 dark:text-purple-400 hover:underline">{{ t.documentation }}</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -202,7 +202,7 @@ After starting (via Docker or locally), wait ~30 seconds for the server to initi
|
||||
|
||||
```bash
|
||||
curl http://localhost:8000/health
|
||||
# Expected: {"status": "ok", "tools_loaded": 589, ...}
|
||||
# Expected: {"status": "ok", "tools_loaded": 596, ...}
|
||||
```
|
||||
|
||||
**2. Open the web dashboard:**
|
||||
@@ -313,7 +313,7 @@ MCP Hub supports **Open Dynamic Client Registration** (RFC 7591). ChatGPT can au
|
||||
|
||||
## Using MCP Tools
|
||||
|
||||
### 589 Tools Across 9 Plugins
|
||||
### 596 Tools Across 9 Plugins
|
||||
|
||||
| Plugin | Tools | Env Prefix |
|
||||
|--------|-------|------------|
|
||||
@@ -326,7 +326,7 @@ MCP Hub supports **Open Dynamic Client Registration** (RFC 7591). ChatGPT can au
|
||||
| OpenPanel | 73 | `OPENPANEL_` |
|
||||
| Appwrite | 100 | `APPWRITE_` |
|
||||
| Directus | 100 | `DIRECTUS_` |
|
||||
| System | 17 | (no config needed) |
|
||||
| System | 24 | (no config needed) |
|
||||
|
||||
### Unified Tool Pattern
|
||||
|
||||
@@ -346,8 +346,8 @@ The `site` parameter accepts either a **site_id** (e.g., `site1`) or an **alias*
|
||||
Use specific endpoints to limit tool access:
|
||||
|
||||
```
|
||||
/mcp → All 589 tools (Master API Key)
|
||||
/system/mcp → System tools only (17 tools)
|
||||
/mcp → All 596 tools (Master API Key)
|
||||
/system/mcp → System tools only (24 tools)
|
||||
/wordpress/mcp → WordPress tools (67 tools)
|
||||
/woocommerce/mcp → WooCommerce tools (28 tools)
|
||||
/gitea/mcp → Gitea tools (56 tools)
|
||||
@@ -448,7 +448,7 @@ The server auto-discovers all `WORDPRESS_*`, `WOOCOMMERCE_*`, `GITEA_*`, and oth
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Explore the full tool list**: See the [README](../README.md) for all 589 tools
|
||||
1. **Explore the full tool list**: See the [README](../README.md) for all 596 tools
|
||||
2. **Set up API keys**: [API Keys Guide](API_KEYS_GUIDE.md) for per-project access control
|
||||
3. **Configure OAuth**: [OAuth Guide](OAUTH_GUIDE.md) for Claude/ChatGPT auto-registration
|
||||
4. **Monitor health**: Use `check_all_projects_health` tool or visit the web dashboard
|
||||
|
||||
32
server.py
32
server.py
@@ -1804,10 +1804,12 @@ def register_project_tools():
|
||||
|
||||
logger.info("=" * 60)
|
||||
|
||||
# System tools count (health + rate limit + API keys):
|
||||
# - 10 system/health/rate limit tools
|
||||
# System tools count:
|
||||
# - 10 health/monitoring/rate-limit tools
|
||||
# - 4 system config tools (endpoints, system_info, audit_log, set_rate_limit_config)
|
||||
# - 6 API key management tools
|
||||
system_tools_count = 16
|
||||
# - 4 OAuth management tools
|
||||
system_tools_count = 24
|
||||
|
||||
total_tools = tool_registry.get_count() + system_tools_count
|
||||
logger.info(
|
||||
@@ -3338,7 +3340,7 @@ def create_system_mcp():
|
||||
"""
|
||||
from fastmcp import FastMCP
|
||||
|
||||
system_instructions = """This is the System Management endpoint (17 tools).
|
||||
system_instructions = """This is the System Management endpoint (24 tools).
|
||||
|
||||
Available tools:
|
||||
• API Key Management: create, list, get_info, revoke, delete, rotate
|
||||
@@ -3455,7 +3457,7 @@ Use get_endpoints() to see all available MCP endpoints."""
|
||||
requests_per_minute, requests_per_hour, requests_per_day
|
||||
)
|
||||
|
||||
logger.info("Created System endpoint with 17 tools")
|
||||
logger.info("Created System endpoint with 24 tools")
|
||||
return system_mcp
|
||||
|
||||
|
||||
@@ -4277,21 +4279,21 @@ def create_multi_endpoint_app(transport: str = "streamable-http"):
|
||||
app = Starlette(routes=routes, lifespan=combined_lifespan, middleware=middleware)
|
||||
|
||||
logger.info("=" * 60)
|
||||
logger.info("Multi-Endpoint Architecture (Phase K) Active")
|
||||
logger.info("Multi-Endpoint Architecture Active")
|
||||
logger.info("=" * 60)
|
||||
logger.info("Dashboard: /dashboard") # Phase K
|
||||
logger.info("Dashboard: /dashboard")
|
||||
logger.info("Endpoints:")
|
||||
logger.info(" /mcp - Admin (all 589 tools)")
|
||||
logger.info(" /system/mcp - System (17 tools)")
|
||||
logger.info(f" /mcp - Admin (all {_total_tool_count} tools)")
|
||||
logger.info(" /system/mcp - System (24 tools)")
|
||||
logger.info(" /wordpress/mcp - WordPress Core (67 tools)")
|
||||
logger.info(" /woocommerce/mcp - WooCommerce (28 tools)") # Phase D.1
|
||||
logger.info(" /woocommerce/mcp - WooCommerce (28 tools)")
|
||||
logger.info(" /wordpress-advanced/mcp - WordPress Advanced (22 tools)")
|
||||
logger.info(" /gitea/mcp - Gitea (56 tools)")
|
||||
logger.info(" /n8n/mcp - n8n Automation (56 tools)") # Phase F
|
||||
logger.info(" /supabase/mcp - Supabase (70 tools)") # Phase G
|
||||
logger.info(" /openpanel/mcp - OpenPanel Analytics (73 tools)") # Phase H
|
||||
logger.info(" /appwrite/mcp - Appwrite Backend (100 tools)") # Phase I
|
||||
logger.info(" /directus/mcp - Directus CMS (100 tools)") # Phase J
|
||||
logger.info(" /n8n/mcp - n8n Automation (56 tools)")
|
||||
logger.info(" /supabase/mcp - Supabase (70 tools)")
|
||||
logger.info(" /openpanel/mcp - OpenPanel Analytics (73 tools)")
|
||||
logger.info(" /appwrite/mcp - Appwrite Backend (100 tools)")
|
||||
logger.info(" /directus/mcp - Directus CMS (100 tools)")
|
||||
|
||||
# Log per-project endpoints
|
||||
if project_apps:
|
||||
|
||||
@@ -64,22 +64,18 @@ class TestPluginDisplayNames:
|
||||
|
||||
|
||||
class TestLanguageDetection:
|
||||
"""Test language detection from headers and query params."""
|
||||
"""Test language detection from query params (default English)."""
|
||||
|
||||
def test_default_english(self):
|
||||
"""Should default to English."""
|
||||
assert detect_language(None) == "en"
|
||||
|
||||
def test_detect_farsi_from_header(self):
|
||||
"""Should detect Farsi from Accept-Language header."""
|
||||
assert detect_language("fa-IR,fa;q=0.9,en;q=0.8") == "fa"
|
||||
def test_header_ignored(self):
|
||||
"""Accept-Language header should be ignored (always default to English)."""
|
||||
assert detect_language("fa-IR,fa;q=0.9,en;q=0.8") == "en"
|
||||
|
||||
def test_detect_farsi_short(self):
|
||||
"""Should detect 'fa' in Accept-Language."""
|
||||
assert detect_language("fa") == "fa"
|
||||
|
||||
def test_query_param_overrides_header(self):
|
||||
"""Query parameter should override Accept-Language header."""
|
||||
def test_query_param_farsi(self):
|
||||
"""Should detect Farsi from explicit query parameter."""
|
||||
assert detect_language("en-US", query_lang="fa") == "fa"
|
||||
|
||||
def test_query_param_english(self):
|
||||
@@ -87,8 +83,8 @@ class TestLanguageDetection:
|
||||
assert detect_language("fa-IR", query_lang="en") == "en"
|
||||
|
||||
def test_invalid_query_lang_ignored(self):
|
||||
"""Invalid query lang should be ignored, fall back to header."""
|
||||
assert detect_language("fa-IR", query_lang="de") == "fa"
|
||||
"""Invalid query lang should be ignored, default to English."""
|
||||
assert detect_language("fa-IR", query_lang="de") == "en"
|
||||
|
||||
def test_english_header(self):
|
||||
"""Should return English for English header."""
|
||||
|
||||
Reference in New Issue
Block a user