docs(onboarding): improve new user experience + fix OpenPanel tools
- Add DOCKER_README.md for Docker Hub overview page
- Fix docker-compose.yaml port mapping for local users ("8000:8000")
- Add "Verify It Works" section with dashboard URL to README
- Restructure env.example with clear REQUIRED section
- Add post-Docker verification checklist to getting-started.md
- Fix 4 OpenPanel tools: parameter ordering (non-default before default)
- Rebrand all "Coolify Projects" to "MCP Hub" in server and Dockerfile
- Make MCP namespace prefix stripping generic
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
124
DOCKER_README.md
Normal file
124
DOCKER_README.md
Normal file
@@ -0,0 +1,124 @@
|
||||
# MCP Hub
|
||||
|
||||
**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.
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Create a `.env` file
|
||||
|
||||
```bash
|
||||
# Required
|
||||
MASTER_API_KEY=your-secure-key-here
|
||||
|
||||
# Add at least one WordPress site
|
||||
WORDPRESS_SITE1_URL=https://your-site.com
|
||||
WORDPRESS_SITE1_USERNAME=admin
|
||||
WORDPRESS_SITE1_APP_PASSWORD=xxxx xxxx xxxx xxxx
|
||||
WORDPRESS_SITE1_ALIAS=mysite
|
||||
```
|
||||
|
||||
### 2. Run the container
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name mcphub \
|
||||
-p 8000:8000 \
|
||||
--env-file .env \
|
||||
airano/mcphub:latest
|
||||
```
|
||||
|
||||
### 3. Verify it works
|
||||
|
||||
```bash
|
||||
# Health check (wait ~30 seconds for startup)
|
||||
curl http://localhost:8000/health
|
||||
|
||||
# Open the web dashboard
|
||||
# http://localhost:8000/dashboard
|
||||
```
|
||||
|
||||
### 4. Connect your AI client
|
||||
|
||||
In Claude Desktop's `claude_desktop_config.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"mcphub": {
|
||||
"url": "http://localhost:8000/mcp",
|
||||
"headers": {
|
||||
"Authorization": "Bearer your-secure-key-here"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Using Docker Compose
|
||||
|
||||
```yaml
|
||||
services:
|
||||
mcphub:
|
||||
image: airano/mcphub:latest
|
||||
ports:
|
||||
- "8000:8000"
|
||||
env_file:
|
||||
- .env
|
||||
volumes:
|
||||
- mcphub-data:/app/data
|
||||
- mcphub-logs:/app/logs
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
mcphub-data:
|
||||
mcphub-logs:
|
||||
```
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
## After Starting
|
||||
|
||||
| URL | Description |
|
||||
|-----|-------------|
|
||||
| `http://localhost:8000/health` | Health check & status |
|
||||
| `http://localhost:8000/dashboard` | Web dashboard (manage API keys, view sites, health) |
|
||||
| `http://localhost:8000/mcp` | MCP endpoint (connect AI clients here) |
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Required | Description |
|
||||
|----------|----------|-------------|
|
||||
| `MASTER_API_KEY` | **Yes** | API key for authentication |
|
||||
| `WORDPRESS_SITE1_URL` | For WP | WordPress site URL |
|
||||
| `WORDPRESS_SITE1_USERNAME` | For WP | WordPress admin username |
|
||||
| `WORDPRESS_SITE1_APP_PASSWORD` | For WP | WordPress Application Password |
|
||||
| `WORDPRESS_SITE1_ALIAS` | Recommended | Friendly name (e.g., `myblog`) |
|
||||
| `OAUTH_JWT_SECRET_KEY` | For OAuth | JWT secret for ChatGPT/Claude auto-registration |
|
||||
| `OAUTH_BASE_URL` | For OAuth | Public URL of your server |
|
||||
|
||||
Add more sites with `SITE2`, `SITE3`, etc. See [full configuration guide](https://github.com/airano-ir/mcphub/blob/main/docs/getting-started.md).
|
||||
|
||||
## Supported Plugins
|
||||
|
||||
| Plugin | Tools | Env Prefix |
|
||||
|--------|-------|------------|
|
||||
| WordPress | 67 | `WORDPRESS_` |
|
||||
| WooCommerce | 28 | `WOOCOMMERCE_` |
|
||||
| WordPress Advanced | 22 | `WORDPRESS_` |
|
||||
| Gitea | 56 | `GITEA_` |
|
||||
| n8n | 56 | `N8N_` |
|
||||
| Supabase | 70 | `SUPABASE_` |
|
||||
| OpenPanel | 73 | `OPENPANEL_` |
|
||||
| Appwrite | 100 | `APPWRITE_` |
|
||||
| Directus | 100 | `DIRECTUS_` |
|
||||
|
||||
## Links
|
||||
|
||||
- **GitHub**: [github.com/airano-ir/mcphub](https://github.com/airano-ir/mcphub)
|
||||
- **PyPI**: [pypi.org/project/mcphub-server](https://pypi.org/project/mcphub-server/)
|
||||
- **Documentation**: [Getting Started Guide](https://github.com/airano-ir/mcphub/blob/main/docs/getting-started.md)
|
||||
- **License**: MIT
|
||||
@@ -1,5 +1,5 @@
|
||||
# ===================================
|
||||
# Coolify Projects MCP Server - Dockerfile
|
||||
# MCP Hub — Dockerfile
|
||||
# ===================================
|
||||
# Multi-stage build for optimized image size
|
||||
# Production-ready with security best practices
|
||||
|
||||
20
README.md
20
README.md
@@ -72,14 +72,15 @@ MCP Hub is the first MCP server that lets you manage WordPress, WooCommerce, and
|
||||
git clone https://github.com/airano-ir/mcphub.git
|
||||
cd mcphub
|
||||
cp env.example .env
|
||||
# Edit .env with your site credentials
|
||||
# Edit .env — set MASTER_API_KEY and add your site credentials
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Option 2: PyPI
|
||||
### Option 2: Docker Hub (No Clone)
|
||||
|
||||
```bash
|
||||
pip install mcphub-server
|
||||
# Create a .env file with your credentials (see "Configure Your Sites" below)
|
||||
docker run -d --name mcphub -p 8000:8000 --env-file .env airano/mcphub:latest
|
||||
```
|
||||
|
||||
### Option 3: From Source
|
||||
@@ -93,6 +94,19 @@ cp env.example .env
|
||||
python server.py --transport sse --port 8000
|
||||
```
|
||||
|
||||
### Verify It Works
|
||||
|
||||
After starting the server, wait ~30 seconds then:
|
||||
|
||||
```bash
|
||||
# Check server health
|
||||
curl http://localhost:8000/health
|
||||
```
|
||||
|
||||
Open the **web dashboard** in your browser: **http://localhost:8000/dashboard**
|
||||
|
||||
You should see the login page. Use your `MASTER_API_KEY` to log in.
|
||||
|
||||
### Configure Your Sites
|
||||
|
||||
Add site credentials to `.env`:
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
# ===================================
|
||||
# MCP Hub — Docker Compose Configuration
|
||||
# ===================================
|
||||
#
|
||||
# Build Pack: Docker Compose
|
||||
# ⚠️ CRITICAL RULES FOR COOLIFY:
|
||||
# 1. NO host port mappings: Use "8000" NOT "8000:8000"
|
||||
# 2. Listen on 0.0.0.0 (NOT localhost)
|
||||
# 3. Health checks for ALL services
|
||||
# 4. Use environment variables for ALL configs
|
||||
#
|
||||
# After starting:
|
||||
# docker compose up -d
|
||||
# curl http://localhost:8000/health # verify server is running
|
||||
# open http://localhost:8000/dashboard # web dashboard
|
||||
#
|
||||
# For Coolify deployments:
|
||||
# Change ports to "8000" (no host mapping) — Coolify handles routing.
|
||||
# ===================================
|
||||
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
mcp-server:
|
||||
build:
|
||||
@@ -19,11 +18,9 @@ services:
|
||||
dockerfile: Dockerfile
|
||||
container_name: mcphub
|
||||
restart: unless-stopped
|
||||
|
||||
# ⚠️ CRITICAL: Only container port (NO host port mapping)
|
||||
# Coolify will handle routing via domain
|
||||
|
||||
ports:
|
||||
- "8000"
|
||||
- "8000:8000"
|
||||
|
||||
# Environment variables
|
||||
environment:
|
||||
|
||||
@@ -48,14 +48,18 @@ For each WordPress site you want to manage:
|
||||
git clone https://github.com/airano-ir/mcphub.git
|
||||
cd mcphub
|
||||
cp env.example .env
|
||||
# Edit .env with your site credentials
|
||||
# Edit .env — set MASTER_API_KEY and add your site credentials (see Configuration below)
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Option 2: PyPI
|
||||
After starting, see [Verify Installation](#verify-installation) below.
|
||||
|
||||
### Option 2: Docker Hub (No Clone)
|
||||
|
||||
```bash
|
||||
pip install mcphub-server
|
||||
# 1. Create a .env file (see Configuration section below)
|
||||
# 2. Run:
|
||||
docker run -d --name mcphub -p 8000:8000 --env-file .env airano/mcphub:latest
|
||||
```
|
||||
|
||||
### Option 3: From Source
|
||||
@@ -190,22 +194,48 @@ python server.py --transport sse --port 8000
|
||||
python server.py
|
||||
```
|
||||
|
||||
### Verify Server is Running
|
||||
### Verify Installation
|
||||
|
||||
Check logs for:
|
||||
After starting (via Docker or locally), wait ~30 seconds for the server to initialize, then:
|
||||
|
||||
```
|
||||
INFO: MCP Hub initialized
|
||||
INFO: Registered 589 tools
|
||||
INFO: Server ready
|
||||
```
|
||||
|
||||
Or test the health endpoint:
|
||||
**1. Check health:**
|
||||
|
||||
```bash
|
||||
curl http://localhost:8000/health
|
||||
# Expected: {"status": "ok", "tools_loaded": 589, ...}
|
||||
```
|
||||
|
||||
**2. Open the web dashboard:**
|
||||
|
||||
Open **http://localhost:8000/dashboard** in your browser. Log in with your `MASTER_API_KEY`.
|
||||
|
||||
The dashboard lets you:
|
||||
- View all connected sites and their health status
|
||||
- Create and manage per-project API keys
|
||||
- View audit logs
|
||||
- Monitor rate limits
|
||||
|
||||
**3. Check container status (Docker only):**
|
||||
|
||||
```bash
|
||||
docker compose ps
|
||||
# Look for Status: "Up (healthy)"
|
||||
# Note: Health check starts after 40 seconds — "starting" is normal initially
|
||||
|
||||
# View logs if something is wrong:
|
||||
docker compose logs -f mcphub
|
||||
```
|
||||
|
||||
**4. Troubleshooting:**
|
||||
|
||||
| Problem | Solution |
|
||||
|---------|----------|
|
||||
| Container exits immediately | Check logs: `docker compose logs mcphub` |
|
||||
| Port 8000 already in use | Change port in docker-compose.yaml: `"8001:8000"` |
|
||||
| Health check shows "unhealthy" | Wait 60 seconds, then check logs for startup errors |
|
||||
| Dashboard login fails | Make sure you're using the `MASTER_API_KEY` value from your `.env` |
|
||||
| Sites not showing up | Restart after adding new env vars: `docker compose restart` |
|
||||
|
||||
---
|
||||
|
||||
## Connect Your AI Client
|
||||
@@ -334,34 +364,40 @@ Use specific endpoints to limit tool access:
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
After starting, verify the installation:
|
||||
|
||||
```bash
|
||||
curl http://localhost:8000/health # server health
|
||||
open http://localhost:8000/dashboard # web dashboard
|
||||
```
|
||||
|
||||
See [Verify Installation](#verify-installation) for detailed steps.
|
||||
|
||||
### Docker Commands
|
||||
|
||||
```bash
|
||||
# View logs
|
||||
docker compose logs -f
|
||||
docker compose logs -f mcphub
|
||||
|
||||
# Check status
|
||||
# Check status (look for "healthy")
|
||||
docker compose ps
|
||||
|
||||
# Restart
|
||||
# Restart (needed after .env changes)
|
||||
docker compose restart
|
||||
|
||||
# Stop
|
||||
docker compose down
|
||||
|
||||
# Rebuild
|
||||
# Rebuild (after code changes)
|
||||
docker compose up --build -d
|
||||
```
|
||||
|
||||
### Health Check
|
||||
### Adding Sites After Startup
|
||||
|
||||
```bash
|
||||
# Check container health
|
||||
docker compose ps
|
||||
|
||||
# Test API endpoint
|
||||
curl http://localhost:8000/health
|
||||
```
|
||||
1. Edit your `.env` file to add new site credentials
|
||||
2. Restart the container: `docker compose restart`
|
||||
3. Verify: `curl http://localhost:8000/health` — check that tools are loaded
|
||||
4. The dashboard at http://localhost:8000/dashboard will show the new sites
|
||||
|
||||
---
|
||||
|
||||
|
||||
49
server.py
49
server.py
@@ -1,9 +1,9 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Coolify Projects MCP Server
|
||||
MCP Hub Server
|
||||
|
||||
Universal MCP server for managing Coolify projects through plugins.
|
||||
Supports WordPress, Supabase, Gitea, and custom project types.
|
||||
Universal MCP server for managing self-hosted services through plugins.
|
||||
Supports WordPress, WooCommerce, Gitea, n8n, Supabase, OpenPanel, Appwrite, and Directus.
|
||||
|
||||
Usage:
|
||||
# With stdio transport (Claude Desktop)
|
||||
@@ -228,7 +228,7 @@ if OAUTH_AUTH_MODE == "trusted_domains":
|
||||
logger.info(f"OAuth Trusted Domains: {', '.join(OAUTH_TRUSTED_DOMAINS)}")
|
||||
|
||||
# Initialize MCP server
|
||||
mcp = FastMCP("Coolify Projects Manager")
|
||||
mcp = FastMCP("MCP Hub")
|
||||
|
||||
# Initialize Jinja2 templates (Phase E - OAuth Authorization Page)
|
||||
templates = Jinja2Templates(directory="templates")
|
||||
@@ -261,7 +261,7 @@ tool_registry = get_tool_registry()
|
||||
tool_generator = ToolGenerator(site_manager)
|
||||
|
||||
logger.info("=" * 60)
|
||||
logger.info("Coolify Projects MCP Server - Option B Clean Architecture")
|
||||
logger.info("MCP Hub Server - Initialized")
|
||||
logger.info("=" * 60)
|
||||
_mk = auth_manager.get_master_key()
|
||||
logger.info(f"Master API Key: {_mk[:8]}***{_mk[-4:]}")
|
||||
@@ -471,10 +471,11 @@ def extract_plugin_type_from_tool(tool_name: str) -> str | None:
|
||||
Returns:
|
||||
Plugin type string or None for system tools
|
||||
"""
|
||||
# Remove MCP namespace prefix if present
|
||||
# Remove MCP namespace prefix if present (e.g., "mcp__mcp-hub__wordpress_...")
|
||||
clean_name = tool_name
|
||||
if tool_name.startswith("mcp__coolify-projects__"):
|
||||
clean_name = tool_name.replace("mcp__coolify-projects__", "")
|
||||
if tool_name.startswith("mcp__") and "__" in tool_name[5:]:
|
||||
# Strip "mcp__{server-name}__" prefix
|
||||
clean_name = tool_name.split("__", 2)[-1]
|
||||
|
||||
# Check for plugin types (order matters - check more specific first)
|
||||
# wordpress_advanced must be checked before wordpress
|
||||
@@ -683,15 +684,15 @@ class UserAuthMiddleware(Middleware):
|
||||
else:
|
||||
# All plugin tools that have a 'site' parameter are unified tools
|
||||
# They defer project access check to execution time
|
||||
# Clean any MCP namespace prefix before checking
|
||||
check_name = tool_name
|
||||
if tool_name.startswith("mcp__") and "__" in tool_name[5:]:
|
||||
check_name = tool_name.split("__", 2)[-1]
|
||||
is_unified_tool = (
|
||||
tool_name.startswith("wordpress_")
|
||||
or tool_name.startswith("wordpress_advanced_")
|
||||
or tool_name.startswith("woocommerce_")
|
||||
or tool_name.startswith("gitea_")
|
||||
or tool_name.startswith("mcp__coolify-projects__wordpress_")
|
||||
or tool_name.startswith("mcp__coolify-projects__wordpress_advanced_")
|
||||
or tool_name.startswith("mcp__coolify-projects__woocommerce_")
|
||||
or tool_name.startswith("mcp__coolify-projects__gitea_")
|
||||
check_name.startswith("wordpress_")
|
||||
or check_name.startswith("wordpress_advanced_")
|
||||
or check_name.startswith("woocommerce_")
|
||||
or check_name.startswith("gitea_")
|
||||
)
|
||||
|
||||
logger.debug(
|
||||
@@ -992,9 +993,11 @@ class RateLimitMiddleware(Middleware):
|
||||
tool_name = params.name if hasattr(params, "name") else "unknown"
|
||||
|
||||
# Determine plugin type from tool name
|
||||
if tool_name.startswith("wordpress_") or tool_name.startswith(
|
||||
"mcp__coolify-projects__wordpress_"
|
||||
):
|
||||
# Clean any MCP namespace prefix
|
||||
tn = tool_name
|
||||
if tool_name.startswith("mcp__") and "__" in tool_name[5:]:
|
||||
tn = tool_name.split("__", 2)[-1]
|
||||
if tn.startswith("wordpress_"):
|
||||
plugin_type = "wordpress"
|
||||
elif tool_name.startswith("woocommerce_"):
|
||||
plugin_type = "woocommerce"
|
||||
@@ -1540,6 +1543,12 @@ def create_dynamic_tool(name: str, description: str, handler, input_schema: dict
|
||||
)
|
||||
)
|
||||
|
||||
# Sort params: required (no default) first, then optional (with default).
|
||||
# Python/inspect.Signature requires non-default args before default args.
|
||||
required_first = [p for p in params if p.default is inspect.Parameter.empty]
|
||||
optional_after = [p for p in params if p.default is not inspect.Parameter.empty]
|
||||
params = required_first + optional_after
|
||||
|
||||
# Create signature
|
||||
sig = inspect.Signature(params)
|
||||
|
||||
@@ -4313,7 +4322,7 @@ def main():
|
||||
import uvicorn
|
||||
|
||||
# Parse command line arguments for transport configuration
|
||||
parser = argparse.ArgumentParser(description="Coolify Projects MCP Server")
|
||||
parser = argparse.ArgumentParser(description="MCP Hub Server")
|
||||
parser.add_argument(
|
||||
"--transport",
|
||||
type=str,
|
||||
|
||||
Reference in New Issue
Block a user