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
|
# Multi-stage build for optimized image size
|
||||||
# Production-ready with security best practices
|
# 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
|
git clone https://github.com/airano-ir/mcphub.git
|
||||||
cd mcphub
|
cd mcphub
|
||||||
cp env.example .env
|
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
|
docker compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
### Option 2: PyPI
|
### Option 2: Docker Hub (No Clone)
|
||||||
|
|
||||||
```bash
|
```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
|
### Option 3: From Source
|
||||||
@@ -93,6 +94,19 @@ cp env.example .env
|
|||||||
python server.py --transport sse --port 8000
|
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
|
### Configure Your Sites
|
||||||
|
|
||||||
Add site credentials to `.env`:
|
Add site credentials to `.env`:
|
||||||
|
|||||||
@@ -2,16 +2,15 @@
|
|||||||
# MCP Hub — Docker Compose Configuration
|
# MCP Hub — Docker Compose Configuration
|
||||||
# ===================================
|
# ===================================
|
||||||
#
|
#
|
||||||
# Build Pack: Docker Compose
|
# After starting:
|
||||||
# ⚠️ CRITICAL RULES FOR COOLIFY:
|
# docker compose up -d
|
||||||
# 1. NO host port mappings: Use "8000" NOT "8000:8000"
|
# curl http://localhost:8000/health # verify server is running
|
||||||
# 2. Listen on 0.0.0.0 (NOT localhost)
|
# open http://localhost:8000/dashboard # web dashboard
|
||||||
# 3. Health checks for ALL services
|
#
|
||||||
# 4. Use environment variables for ALL configs
|
# For Coolify deployments:
|
||||||
|
# Change ports to "8000" (no host mapping) — Coolify handles routing.
|
||||||
# ===================================
|
# ===================================
|
||||||
|
|
||||||
version: '3.8'
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
mcp-server:
|
mcp-server:
|
||||||
build:
|
build:
|
||||||
@@ -20,10 +19,8 @@ services:
|
|||||||
container_name: mcphub
|
container_name: mcphub
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
# ⚠️ CRITICAL: Only container port (NO host port mapping)
|
|
||||||
# Coolify will handle routing via domain
|
|
||||||
ports:
|
ports:
|
||||||
- "8000"
|
- "8000:8000"
|
||||||
|
|
||||||
# Environment variables
|
# Environment variables
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@@ -48,14 +48,18 @@ For each WordPress site you want to manage:
|
|||||||
git clone https://github.com/airano-ir/mcphub.git
|
git clone https://github.com/airano-ir/mcphub.git
|
||||||
cd mcphub
|
cd mcphub
|
||||||
cp env.example .env
|
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
|
docker compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
### Option 2: PyPI
|
After starting, see [Verify Installation](#verify-installation) below.
|
||||||
|
|
||||||
|
### Option 2: Docker Hub (No Clone)
|
||||||
|
|
||||||
```bash
|
```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
|
### Option 3: From Source
|
||||||
@@ -190,22 +194,48 @@ python server.py --transport sse --port 8000
|
|||||||
python server.py
|
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:
|
||||||
|
|
||||||
```
|
**1. Check health:**
|
||||||
INFO: MCP Hub initialized
|
|
||||||
INFO: Registered 589 tools
|
|
||||||
INFO: Server ready
|
|
||||||
```
|
|
||||||
|
|
||||||
Or test the health endpoint:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl http://localhost:8000/health
|
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
|
## Connect Your AI Client
|
||||||
@@ -334,34 +364,40 @@ Use specific endpoints to limit tool access:
|
|||||||
docker compose up -d
|
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
|
### Docker Commands
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# View logs
|
# View logs
|
||||||
docker compose logs -f
|
docker compose logs -f mcphub
|
||||||
|
|
||||||
# Check status
|
# Check status (look for "healthy")
|
||||||
docker compose ps
|
docker compose ps
|
||||||
|
|
||||||
# Restart
|
# Restart (needed after .env changes)
|
||||||
docker compose restart
|
docker compose restart
|
||||||
|
|
||||||
# Stop
|
# Stop
|
||||||
docker compose down
|
docker compose down
|
||||||
|
|
||||||
# Rebuild
|
# Rebuild (after code changes)
|
||||||
docker compose up --build -d
|
docker compose up --build -d
|
||||||
```
|
```
|
||||||
|
|
||||||
### Health Check
|
### Adding Sites After Startup
|
||||||
|
|
||||||
```bash
|
1. Edit your `.env` file to add new site credentials
|
||||||
# Check container health
|
2. Restart the container: `docker compose restart`
|
||||||
docker compose ps
|
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
|
||||||
# Test API endpoint
|
|
||||||
curl http://localhost:8000/health
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
49
server.py
49
server.py
@@ -1,9 +1,9 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
Coolify Projects MCP Server
|
MCP Hub Server
|
||||||
|
|
||||||
Universal MCP server for managing Coolify projects through plugins.
|
Universal MCP server for managing self-hosted services through plugins.
|
||||||
Supports WordPress, Supabase, Gitea, and custom project types.
|
Supports WordPress, WooCommerce, Gitea, n8n, Supabase, OpenPanel, Appwrite, and Directus.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
# With stdio transport (Claude Desktop)
|
# 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)}")
|
logger.info(f"OAuth Trusted Domains: {', '.join(OAUTH_TRUSTED_DOMAINS)}")
|
||||||
|
|
||||||
# Initialize MCP server
|
# Initialize MCP server
|
||||||
mcp = FastMCP("Coolify Projects Manager")
|
mcp = FastMCP("MCP Hub")
|
||||||
|
|
||||||
# Initialize Jinja2 templates (Phase E - OAuth Authorization Page)
|
# Initialize Jinja2 templates (Phase E - OAuth Authorization Page)
|
||||||
templates = Jinja2Templates(directory="templates")
|
templates = Jinja2Templates(directory="templates")
|
||||||
@@ -261,7 +261,7 @@ tool_registry = get_tool_registry()
|
|||||||
tool_generator = ToolGenerator(site_manager)
|
tool_generator = ToolGenerator(site_manager)
|
||||||
|
|
||||||
logger.info("=" * 60)
|
logger.info("=" * 60)
|
||||||
logger.info("Coolify Projects MCP Server - Option B Clean Architecture")
|
logger.info("MCP Hub Server - Initialized")
|
||||||
logger.info("=" * 60)
|
logger.info("=" * 60)
|
||||||
_mk = auth_manager.get_master_key()
|
_mk = auth_manager.get_master_key()
|
||||||
logger.info(f"Master API Key: {_mk[:8]}***{_mk[-4:]}")
|
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:
|
Returns:
|
||||||
Plugin type string or None for system tools
|
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
|
clean_name = tool_name
|
||||||
if tool_name.startswith("mcp__coolify-projects__"):
|
if tool_name.startswith("mcp__") and "__" in tool_name[5:]:
|
||||||
clean_name = tool_name.replace("mcp__coolify-projects__", "")
|
# Strip "mcp__{server-name}__" prefix
|
||||||
|
clean_name = tool_name.split("__", 2)[-1]
|
||||||
|
|
||||||
# Check for plugin types (order matters - check more specific first)
|
# Check for plugin types (order matters - check more specific first)
|
||||||
# wordpress_advanced must be checked before wordpress
|
# wordpress_advanced must be checked before wordpress
|
||||||
@@ -683,15 +684,15 @@ class UserAuthMiddleware(Middleware):
|
|||||||
else:
|
else:
|
||||||
# All plugin tools that have a 'site' parameter are unified tools
|
# All plugin tools that have a 'site' parameter are unified tools
|
||||||
# They defer project access check to execution time
|
# 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 = (
|
is_unified_tool = (
|
||||||
tool_name.startswith("wordpress_")
|
check_name.startswith("wordpress_")
|
||||||
or tool_name.startswith("wordpress_advanced_")
|
or check_name.startswith("wordpress_advanced_")
|
||||||
or tool_name.startswith("woocommerce_")
|
or check_name.startswith("woocommerce_")
|
||||||
or tool_name.startswith("gitea_")
|
or check_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_")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
logger.debug(
|
logger.debug(
|
||||||
@@ -992,9 +993,11 @@ class RateLimitMiddleware(Middleware):
|
|||||||
tool_name = params.name if hasattr(params, "name") else "unknown"
|
tool_name = params.name if hasattr(params, "name") else "unknown"
|
||||||
|
|
||||||
# Determine plugin type from tool name
|
# Determine plugin type from tool name
|
||||||
if tool_name.startswith("wordpress_") or tool_name.startswith(
|
# Clean any MCP namespace prefix
|
||||||
"mcp__coolify-projects__wordpress_"
|
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"
|
plugin_type = "wordpress"
|
||||||
elif tool_name.startswith("woocommerce_"):
|
elif tool_name.startswith("woocommerce_"):
|
||||||
plugin_type = "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
|
# Create signature
|
||||||
sig = inspect.Signature(params)
|
sig = inspect.Signature(params)
|
||||||
|
|
||||||
@@ -4313,7 +4322,7 @@ def main():
|
|||||||
import uvicorn
|
import uvicorn
|
||||||
|
|
||||||
# Parse command line arguments for transport configuration
|
# 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(
|
parser.add_argument(
|
||||||
"--transport",
|
"--transport",
|
||||||
type=str,
|
type=str,
|
||||||
|
|||||||
Reference in New Issue
Block a user