sync: v3.2.0 pre-release audit — namespace fix, config types, docs update
- fix(seo): REST API namespace seo-api-bridge/v1 → airano-mcp-seo-bridge/v1 - fix(config): add transport type field (streamableHttp/http) to config snippets - feat(dashboard): support section for OAuth users, connect page guidance - docs: hosted option, test count 481, WP plugin link, OAuth env vars, per-user endpoints Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -179,7 +179,7 @@ Types: `feat`, `fix`, `docs`, `style`, `refactor`, `test`, `chore`
|
|||||||
|
|
||||||
- Test files exist in both `tests/` (proper) and root directory (legacy `test_*.py`). Run `pytest tests/` for organized tests only.
|
- 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
|
- `server_multi.py` is the alternative multi-endpoint entry point; `server.py` is the primary
|
||||||
- `wordpress-plugin/` contains companion WP plugins (openpanel, seo-api-bridge) — these are PHP, not Python
|
- `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
|
- `env.example` has "FUTURE" labels for Supabase/Gitea but both are fully implemented
|
||||||
- Dashboard templates live in `core/templates/` (included in pip package as `package_data`)
|
- 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)
|
- `ruff` config uses top-level `select` key in pyproject.toml (not `[tool.ruff.lint]` nested format)
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ Then register in `plugins/__init__.py` and add tests.
|
|||||||
core/ # Core system (auth, site manager, tool registry, dashboard)
|
core/ # Core system (auth, site manager, tool registry, dashboard)
|
||||||
plugins/ # Plugin system (9 plugins, each with handlers + schemas)
|
plugins/ # Plugin system (9 plugins, each with handlers + schemas)
|
||||||
core/templates/ # Jinja2 templates (dashboard + OAuth)
|
core/templates/ # Jinja2 templates (dashboard + OAuth)
|
||||||
tests/ # Test suite (290 tests)
|
tests/ # Test suite (481 tests)
|
||||||
scripts/ # Setup & deployment scripts
|
scripts/ # Setup & deployment scripts
|
||||||
docs/ # Documentation
|
docs/ # Documentation
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
596 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.
|
||||||
|
|
||||||
|
> **Don't want to self-host?** Try the hosted instance at **[mcp.palebluedot.live](https://mcp.palebluedot.live)** — log in with GitHub or Google, add your sites, and connect your AI client in minutes.
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
### 1. Create a `.env` file
|
### 1. Create a `.env` file
|
||||||
@@ -91,6 +93,7 @@ Use the most specific endpoint for your use case:
|
|||||||
|
|
||||||
| Endpoint | Tools | `site` param? | Best for |
|
| Endpoint | Tools | `site` param? | Best for |
|
||||||
|----------|------:|:-------------:|----------|
|
|----------|------:|:-------------:|----------|
|
||||||
|
| `/u/{user_id}/{alias}/mcp` | 22-100 | No (pre-scoped) | Hosted/OAuth users |
|
||||||
| `/project/{alias}/mcp` | 22-100 | No (pre-scoped) | Single-site workflow |
|
| `/project/{alias}/mcp` | 22-100 | No (pre-scoped) | Single-site workflow |
|
||||||
| `/{plugin}/mcp` | 23-101 | Yes | Multi-site management |
|
| `/{plugin}/mcp` | 23-101 | Yes | Multi-site management |
|
||||||
| `/mcp` | 596 | Yes | Admin & discovery only |
|
| `/mcp` | 596 | Yes | Admin & discovery only |
|
||||||
@@ -131,7 +134,7 @@ docker compose up -d
|
|||||||
| URL | Description |
|
| URL | Description |
|
||||||
|-----|-------------|
|
|-----|-------------|
|
||||||
| `http://localhost:8000/health` | Health check & status |
|
| `http://localhost:8000/health` | Health check & status |
|
||||||
| `http://localhost:8000/dashboard` | Web dashboard (manage API keys, view sites, health) |
|
| `http://localhost:8000/dashboard` | Web dashboard (manage sites, API keys, OAuth clients, health monitoring). Login via MASTER_API_KEY or GitHub/Google OAuth |
|
||||||
| `http://localhost:8000/mcp` | MCP endpoint (connect AI clients here) |
|
| `http://localhost:8000/mcp` | MCP endpoint (connect AI clients here) |
|
||||||
|
|
||||||
## Environment Variables
|
## Environment Variables
|
||||||
@@ -146,11 +149,19 @@ docker compose up -d
|
|||||||
| `WORDPRESS_SITE1_CONTAINER` | For WP-CLI | Docker container name of your WordPress site (enables cache/db/system tools) |
|
| `WORDPRESS_SITE1_CONTAINER` | For WP-CLI | Docker container name of your WordPress site (enables cache/db/system tools) |
|
||||||
| `OAUTH_JWT_SECRET_KEY` | For OAuth | JWT secret for ChatGPT auto-registration (not needed for Claude/Cursor) |
|
| `OAUTH_JWT_SECRET_KEY` | For OAuth | JWT secret for ChatGPT auto-registration (not needed for Claude/Cursor) |
|
||||||
| `OAUTH_BASE_URL` | For OAuth | Public URL of your server (not needed for Claude/Cursor) |
|
| `OAUTH_BASE_URL` | For OAuth | Public URL of your server (not needed for Claude/Cursor) |
|
||||||
|
| `GITHUB_CLIENT_ID` | For Social Login | GitHub OAuth App client ID |
|
||||||
|
| `GITHUB_CLIENT_SECRET` | For Social Login | GitHub OAuth App client secret |
|
||||||
|
| `GOOGLE_CLIENT_ID` | For Social Login | Google OAuth client ID |
|
||||||
|
| `GOOGLE_CLIENT_SECRET` | For Social Login | Google OAuth client secret |
|
||||||
|
| `PUBLIC_URL` | For Social Login | Public URL for OAuth callbacks (e.g., `https://mcp.example.com`) |
|
||||||
|
| `ENCRYPTION_KEY` | For Multi-user | AES-256 key for encrypting user site credentials. Generate: `python -c "import os, base64; print(base64.b64encode(os.urandom(32)).decode())"` |
|
||||||
|
|
||||||
> **CONTAINER**: Required for WP-CLI tools (cache flush, database export, system info) and **all** WordPress Advanced tools. Find your container name: `docker ps --filter name=wordpress`. Also requires Docker socket mount.
|
> **CONTAINER**: Required for WP-CLI tools (cache flush, database export, system info) and **all** WordPress Advanced tools. Find your container name: `docker ps --filter name=wordpress`. Also requires Docker socket mount.
|
||||||
|
|
||||||
> **OAuth**: Only needed for ChatGPT Remote MCP auto-registration. For Claude Desktop, Claude Code, Cursor, and VS Code — just use `MASTER_API_KEY` with Bearer token auth.
|
> **OAuth**: Only needed for ChatGPT Remote MCP auto-registration. For Claude Desktop, Claude Code, Cursor, and VS Code — just use `MASTER_API_KEY` with Bearer token auth.
|
||||||
|
|
||||||
|
> **Social Login**: Enable GitHub/Google login for multi-user mode. Users can add sites via the dashboard and get personal MCP endpoints (`/u/{user_id}/{alias}/mcp`).
|
||||||
|
|
||||||
Add more sites with `SITE2`, `SITE3`, etc. See [full configuration guide](https://github.com/airano-ir/mcphub/blob/main/docs/getting-started.md).
|
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
|
## Supported Plugins
|
||||||
|
|||||||
23
README.md
23
README.md
@@ -13,7 +13,7 @@ Connect your sites, stores, repos, and databases — manage them all through Cla
|
|||||||
[](https://www.python.org/)
|
[](https://www.python.org/)
|
||||||
[](https://pypi.org/project/mcphub-server/)
|
[](https://pypi.org/project/mcphub-server/)
|
||||||
[](https://hub.docker.com/r/airano/mcphub)
|
[](https://hub.docker.com/r/airano/mcphub)
|
||||||
[]()
|
[]()
|
||||||
[]()
|
[]()
|
||||||
[](https://github.com/airano-ir/mcphub/actions/workflows/ci.yml)
|
[](https://github.com/airano-ir/mcphub/actions/workflows/ci.yml)
|
||||||
|
|
||||||
@@ -108,7 +108,20 @@ curl http://localhost:8000/health
|
|||||||
|
|
||||||
Open the **web dashboard** in your browser: **http://localhost:8000/dashboard**
|
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.
|
You should see the login page. Log in with your `MASTER_API_KEY` or via **GitHub/Google OAuth** (if configured).
|
||||||
|
|
||||||
|
### Try It Now (No Setup Required)
|
||||||
|
|
||||||
|
**Don't want to self-host?** Use the hosted instance at **[mcp.example.com](https://mcp.example.com)**:
|
||||||
|
|
||||||
|
1. Log in with **GitHub** or **Google**
|
||||||
|
2. Add your sites via the dashboard (My Sites → Add Service)
|
||||||
|
3. Go to **Connect** page — generate config for your AI client
|
||||||
|
4. Copy-paste the config into Claude Desktop, VS Code, or Claude Code
|
||||||
|
|
||||||
|
Your personal MCP endpoint: `https://mcp.example.com/u/{your-user-id}/{alias}/mcp`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### Configure Your Sites
|
### Configure Your Sites
|
||||||
|
|
||||||
@@ -297,12 +310,14 @@ MCP Hub supports **Open Dynamic Client Registration** (RFC 7591). ChatGPT can au
|
|||||||
/appwrite/mcp → Appwrite tools (100 tools)
|
/appwrite/mcp → Appwrite tools (100 tools)
|
||||||
/directus/mcp → Directus tools (100 tools)
|
/directus/mcp → Directus tools (100 tools)
|
||||||
/project/{alias}/mcp → Per-project endpoint (auto-injects site)
|
/project/{alias}/mcp → Per-project endpoint (auto-injects site)
|
||||||
|
/u/{user_id}/{alias}/mcp → Per-user endpoint (hosted/OAuth users)
|
||||||
```
|
```
|
||||||
|
|
||||||
**Recommendation**: Use plugin-specific endpoints instead of `/mcp` (596 tools) to minimize token usage.
|
**Recommendation**: Use plugin-specific endpoints instead of `/mcp` (596 tools) to minimize token usage.
|
||||||
|
|
||||||
| Endpoint | Use Case | Tools |
|
| Endpoint | Use Case | Tools |
|
||||||
|----------|----------|------:|
|
|----------|----------|------:|
|
||||||
|
| `/u/{user_id}/{alias}/mcp` | Hosted users (OAuth login) | 22-100 |
|
||||||
| `/project/{alias}/mcp` | Single-site workflow (recommended) | 22-100 |
|
| `/project/{alias}/mcp` | Single-site workflow (recommended) | 22-100 |
|
||||||
| `/{plugin}/mcp` | Multi-site management | 23-101 |
|
| `/{plugin}/mcp` | Multi-site management | 23-101 |
|
||||||
| `/mcp` | Admin & discovery only | 596 |
|
| `/mcp` | Admin & discovery only | 596 |
|
||||||
@@ -323,7 +338,7 @@ Some MCP Hub tools require companion WordPress plugins:
|
|||||||
|
|
||||||
| Tools | Requirement |
|
| Tools | Requirement |
|
||||||
|-------|-------------|
|
|-------|-------------|
|
||||||
| SEO tools (`wordpress_get_post_seo`, etc.) | [SEO API Bridge](wordpress-plugin/seo-api-bridge/) ([Download ZIP](wordpress-plugin/seo-api-bridge.zip)) + Rank Math or Yoast SEO |
|
| SEO tools (`wordpress_get_post_seo`, etc.) | [Airano MCP SEO Bridge](https://wordpress.org/plugins/airano-mcp-seo-bridge/) ([GitHub](wordpress-plugin/airano-mcp-seo-bridge/)) + Rank Math or Yoast SEO |
|
||||||
| WP-CLI tools (15 tools: `wp_cache_*`, `wp_db_*`, etc.) | Docker socket + `CONTAINER` env var |
|
| WP-CLI tools (15 tools: `wp_cache_*`, `wp_db_*`, etc.) | Docker socket + `CONTAINER` env var |
|
||||||
| WordPress Advanced database/system tools | Docker socket + `CONTAINER` env var |
|
| WordPress Advanced database/system tools | Docker socket + `CONTAINER` env var |
|
||||||
| OpenPanel analytics integration | [OpenPanel Self-Hosted](wordpress-plugin/openpanel-self-hosted/) ([Download ZIP](wordpress-plugin/openpanel-self-hosted.zip)) |
|
| OpenPanel analytics integration | [OpenPanel Self-Hosted](wordpress-plugin/openpanel-self-hosted/) ([Download ZIP](wordpress-plugin/openpanel-self-hosted.zip)) |
|
||||||
@@ -363,7 +378,7 @@ Without Docker socket, WP-CLI tools return "not available" but all REST API tool
|
|||||||
# Install with dev dependencies
|
# Install with dev dependencies
|
||||||
pip install -e ".[dev]"
|
pip install -e ".[dev]"
|
||||||
|
|
||||||
# Run tests (290 tests)
|
# Run tests (481 tests)
|
||||||
pytest
|
pytest
|
||||||
|
|
||||||
# Format and lint
|
# Format and lint
|
||||||
|
|||||||
@@ -79,10 +79,14 @@ def generate_config(
|
|||||||
endpoint_url = f"{base_url}/u/{user_id}/{alias}/mcp"
|
endpoint_url = f"{base_url}/u/{user_id}/{alias}/mcp"
|
||||||
server_name = f"mcphub-{alias}"
|
server_name = f"mcphub-{alias}"
|
||||||
|
|
||||||
|
# Claude Desktop uses streamableHttp; Claude Code, VS Code, Cursor use http
|
||||||
|
transport_type = "streamableHttp" if client_type == "claude_desktop" else "http"
|
||||||
|
|
||||||
if client_type in ("claude_desktop", "claude_code"):
|
if client_type in ("claude_desktop", "claude_code"):
|
||||||
config = {
|
config = {
|
||||||
"mcpServers": {
|
"mcpServers": {
|
||||||
server_name: {
|
server_name: {
|
||||||
|
"type": transport_type,
|
||||||
"url": endpoint_url,
|
"url": endpoint_url,
|
||||||
"headers": {
|
"headers": {
|
||||||
"Authorization": f"Bearer {api_key}",
|
"Authorization": f"Bearer {api_key}",
|
||||||
@@ -97,6 +101,7 @@ def generate_config(
|
|||||||
"mcp": {
|
"mcp": {
|
||||||
"servers": {
|
"servers": {
|
||||||
server_name: {
|
server_name: {
|
||||||
|
"type": transport_type,
|
||||||
"url": endpoint_url,
|
"url": endpoint_url,
|
||||||
"headers": {
|
"headers": {
|
||||||
"Authorization": f"Bearer {api_key}",
|
"Authorization": f"Bearer {api_key}",
|
||||||
|
|||||||
@@ -127,6 +127,32 @@
|
|||||||
<pre id="config-output" class="bg-gray-100 dark:bg-gray-900 rounded-lg p-4 text-sm text-gray-700 dark:text-gray-300 overflow-x-auto border border-gray-200 dark:border-gray-700 min-h-[120px]">Select a site and client to generate configuration...</pre>
|
<pre id="config-output" class="bg-gray-100 dark:bg-gray-900 rounded-lg p-4 text-sm text-gray-700 dark:text-gray-300 overflow-x-auto border border-gray-200 dark:border-gray-700 min-h-[120px]">Select a site and client to generate configuration...</pre>
|
||||||
<button onclick="copyConfig()" class="absolute top-2 {{ 'left-2' if lang == 'fa' else 'right-2' }} text-xs bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 dark:hover:bg-gray-600 text-gray-600 dark:text-gray-300 px-3 py-1 rounded transition-colors" id="copy-config-btn">{{ t['copy'] }}</button>
|
<button onclick="copyConfig()" class="absolute top-2 {{ 'left-2' if lang == 'fa' else 'right-2' }} text-xs bg-gray-200 dark:bg-gray-700 hover:bg-gray-300 dark:hover:bg-gray-600 text-gray-600 dark:text-gray-300 px-3 py-1 rounded transition-colors" id="copy-config-btn">{{ t['copy'] }}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Transport type info -->
|
||||||
|
<div class="mt-4 bg-blue-50 dark:bg-blue-500/10 border border-blue-200 dark:border-blue-500/30 rounded-lg p-4">
|
||||||
|
<p class="text-sm text-blue-700 dark:text-blue-400">
|
||||||
|
{% if lang == 'fa' %}
|
||||||
|
<strong>نکته:</strong> تنظیمات بالا شامل نوع اتصال (<code>streamableHttp</code> برای Claude Desktop و <code>http</code> برای VS Code/Claude Code) میباشد. از <code>sse</code> استفاده نکنید — باعث خطای <code>400 Bad Request</code> میشود.
|
||||||
|
{% else %}
|
||||||
|
<strong>Note:</strong> Config above includes the correct transport type (<code>streamableHttp</code> for Claude Desktop, <code>http</code> for VS Code/Claude Code). Do not use <code>sse</code> — it will cause <code>400 Bad Request</code> errors.
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- WordPress plugin requirement -->
|
||||||
|
<div class="mt-3 bg-amber-50 dark:bg-amber-500/10 border border-amber-200 dark:border-amber-500/30 rounded-lg p-4">
|
||||||
|
<p class="text-sm text-amber-700 dark:text-amber-400">
|
||||||
|
{% if lang == 'fa' %}
|
||||||
|
<strong>وردپرس:</strong> برای استفاده از ابزارهای SEO، افزونه
|
||||||
|
<a href="https://wordpress.org/plugins/airano-mcp-seo-bridge/" target="_blank" class="underline">Airano MCP SEO Bridge</a>
|
||||||
|
را روی سایت وردپرسی خود نصب کنید. همچنین یک <strong>Application Password</strong> در وردپرس (Users → Profile) ایجاد و هنگام افزودن سایت وارد کنید.
|
||||||
|
{% else %}
|
||||||
|
<strong>WordPress:</strong> For SEO tools, install the
|
||||||
|
<a href="https://wordpress.org/plugins/airano-mcp-seo-bridge/" target="_blank" class="underline">Airano MCP SEO Bridge</a>
|
||||||
|
plugin on your WordPress site. Also create an <strong>Application Password</strong> in WordPress (Users → Profile) and enter it when adding your site.
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p class="text-gray-500 dark:text-gray-400 text-sm">{{ t.no_sites }}. <a href="/dashboard/sites/add{% if lang and lang != 'en' %}?lang={{ lang }}{% endif %}" class="text-blue-600 dark:text-blue-400 hover:text-blue-500 dark:hover:text-blue-300">{{ t.add_site }}</a></p>
|
<p class="text-gray-500 dark:text-gray-400 text-sm">{{ t.no_sites }}. <a href="/dashboard/sites/add{% if lang and lang != 'en' %}?lang={{ lang }}{% endif %}" class="text-blue-600 dark:text-blue-400 hover:text-blue-500 dark:hover:text-blue-300">{{ t.add_site }}</a></p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -439,6 +439,34 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Support / Donate (User Dashboard) -->
|
||||||
|
<div class="bg-gradient-to-br from-primary-900/40 to-gray-800 rounded-xl border border-primary-700/30">
|
||||||
|
<div class="p-6 text-center">
|
||||||
|
<div class="w-10 h-10 bg-primary-500/20 rounded-full flex items-center justify-center mx-auto mb-3">
|
||||||
|
<svg class="w-5 h-5 text-primary-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3 class="text-sm font-semibold text-white mb-1">
|
||||||
|
{% if lang == 'fa' %}حمایت از پروژه{% else %}Support MCP Hub{% endif %}
|
||||||
|
</h3>
|
||||||
|
<p class="text-xs text-gray-400 mb-4">
|
||||||
|
{% if lang == 'fa' %}با حمایت مالی به توسعه این پروژه کمک کنید{% else %}Help us keep this project alive and growing{% endif %}
|
||||||
|
</p>
|
||||||
|
<a
|
||||||
|
href="https://nowpayments.io/donation/airano"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
class="inline-flex items-center px-4 py-2 text-sm font-medium text-white bg-primary-600 hover:bg-primary-500 rounded-lg transition-colors"
|
||||||
|
>
|
||||||
|
<svg class="w-4 h-4 {% if lang == 'fa' %}ml-2{% else %}mr-2{% endif %}" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
||||||
|
</svg>
|
||||||
|
{% if lang == 'fa' %}حمایت با رمزارز{% else %}Donate with Crypto{% endif %}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -42,6 +42,27 @@ For each WordPress site you want to manage:
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
### Option 0: Use Hosted Version (No Setup Required)
|
||||||
|
|
||||||
|
The fastest way to try MCP Hub — no installation needed:
|
||||||
|
|
||||||
|
1. Visit **[mcp.example.com](https://mcp.example.com)**
|
||||||
|
2. Log in with **GitHub** or **Google**
|
||||||
|
3. Add your sites via the dashboard (**My Sites → Add Service**)
|
||||||
|
4. Go to **Connect** page to generate your AI client config
|
||||||
|
5. Copy-paste into Claude Desktop, VS Code, or Claude Code
|
||||||
|
|
||||||
|
Your personal MCP endpoint:
|
||||||
|
```
|
||||||
|
https://mcp.example.com/u/{your-user-id}/{alias}/mcp
|
||||||
|
```
|
||||||
|
|
||||||
|
**WordPress users:** Install the [Airano MCP SEO Bridge](https://wordpress.org/plugins/airano-mcp-seo-bridge/) plugin for SEO tools, and create an [Application Password](https://make.wordpress.org/core/2020/11/05/application-passwords-integration-guide/) (Users → Profile) for authentication.
|
||||||
|
|
||||||
|
> If you prefer self-hosting, continue with the options below.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### Option 1: Docker (Recommended)
|
### Option 1: Docker (Recommended)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -162,6 +183,21 @@ GITEA_REPO1_ALIAS=mygitea
|
|||||||
OAUTH_JWT_SECRET_KEY=your-jwt-secret
|
OAUTH_JWT_SECRET_KEY=your-jwt-secret
|
||||||
OAUTH_BASE_URL=https://your-server:8000
|
OAUTH_BASE_URL=https://your-server:8000
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Social Login (GitHub/Google OAuth — for hosted/multi-user)
|
||||||
|
# ============================================
|
||||||
|
GITHUB_CLIENT_ID=your-github-oauth-app-id
|
||||||
|
GITHUB_CLIENT_SECRET=your-github-oauth-app-secret
|
||||||
|
GOOGLE_CLIENT_ID=your-google-oauth-client-id
|
||||||
|
GOOGLE_CLIENT_SECRET=your-google-oauth-client-secret
|
||||||
|
PUBLIC_URL=https://your-server:8000
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# Encryption (required for storing user site credentials)
|
||||||
|
# ============================================
|
||||||
|
# Generate: python -c "import os, base64; print(base64.b64encode(os.urandom(32)).decode())"
|
||||||
|
ENCRYPTION_KEY=your-base64-encoded-32-byte-key
|
||||||
|
|
||||||
# ============================================
|
# ============================================
|
||||||
# Optional
|
# Optional
|
||||||
# ============================================
|
# ============================================
|
||||||
@@ -327,13 +363,15 @@ curl http://localhost:8000/health
|
|||||||
|
|
||||||
**2. Open the web dashboard:**
|
**2. Open the web dashboard:**
|
||||||
|
|
||||||
Open **http://localhost:8000/dashboard** in your browser. Log in with your `MASTER_API_KEY`.
|
Open **http://localhost:8000/dashboard** in your browser. Log in with your `MASTER_API_KEY` or via **GitHub/Google OAuth** (if configured).
|
||||||
|
|
||||||
The dashboard lets you:
|
The dashboard lets you:
|
||||||
- View all connected sites and their health status
|
- View all connected sites and their health status
|
||||||
|
- **Add, edit, delete, and test sites** via the My Sites page (OAuth users)
|
||||||
- Create and manage per-project API keys
|
- Create and manage per-project API keys
|
||||||
- View audit logs
|
- **Generate AI client configs** on the Connect page (with correct transport type per client)
|
||||||
- Monitor rate limits
|
- View audit logs and monitor rate limits
|
||||||
|
- **Per-user MCP endpoints**: OAuth users get personal endpoints at `/u/{user_id}/{alias}/mcp` with `mhu_` API keys
|
||||||
|
|
||||||
**3. Check container status (Docker only):**
|
**3. Check container status (Docker only):**
|
||||||
|
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ class WordPressClient:
|
|||||||
"""
|
"""
|
||||||
# Build URL based on endpoint type
|
# Build URL based on endpoint type
|
||||||
if use_custom_namespace:
|
if use_custom_namespace:
|
||||||
# For custom namespaces like seo-api-bridge/v1
|
# For custom namespaces like airano-mcp-seo-bridge/v1
|
||||||
url = f"{self.site_url}/wp-json/{endpoint}"
|
url = f"{self.site_url}/wp-json/{endpoint}"
|
||||||
elif use_woocommerce:
|
elif use_woocommerce:
|
||||||
# For WooCommerce endpoints
|
# For WooCommerce endpoints
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ class SEOHandler:
|
|||||||
# First, try to use the new health check endpoint (v1.1.0+)
|
# First, try to use the new health check endpoint (v1.1.0+)
|
||||||
try:
|
try:
|
||||||
status_result = await self.client.get(
|
status_result = await self.client.get(
|
||||||
"seo-api-bridge/v1/status", use_custom_namespace=True
|
"airano-mcp-seo-bridge/v1/status", use_custom_namespace=True
|
||||||
)
|
)
|
||||||
|
|
||||||
if status_result and isinstance(status_result, dict):
|
if status_result and isinstance(status_result, dict):
|
||||||
@@ -383,7 +383,7 @@ class SEOHandler:
|
|||||||
try:
|
try:
|
||||||
# Use SEO API Bridge endpoint for products (same as update_product_seo)
|
# Use SEO API Bridge endpoint for products (same as update_product_seo)
|
||||||
result = await self.client.get(
|
result = await self.client.get(
|
||||||
f"seo-api-bridge/v1/products/{product_id}/seo", use_custom_namespace=True
|
f"airano-mcp-seo-bridge/v1/products/{product_id}/seo", use_custom_namespace=True
|
||||||
)
|
)
|
||||||
|
|
||||||
return json.dumps(result, indent=2)
|
return json.dumps(result, indent=2)
|
||||||
@@ -592,7 +592,7 @@ class SEOHandler:
|
|||||||
|
|
||||||
# Use SEO API Bridge endpoint for products
|
# Use SEO API Bridge endpoint for products
|
||||||
await self.client.post(
|
await self.client.post(
|
||||||
f"seo-api-bridge/v1/products/{product_id}/seo",
|
f"airano-mcp-seo-bridge/v1/products/{product_id}/seo",
|
||||||
json_data=data,
|
json_data=data,
|
||||||
use_custom_namespace=True,
|
use_custom_namespace=True,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -60,16 +60,18 @@ class TestClaudeFormat:
|
|||||||
assert server_name in config["mcpServers"]
|
assert server_name in config["mcpServers"]
|
||||||
server = config["mcpServers"][server_name]
|
server = config["mcpServers"][server_name]
|
||||||
assert server["url"] == EXPECTED_ENDPOINT
|
assert server["url"] == EXPECTED_ENDPOINT
|
||||||
|
assert server["type"] == "streamableHttp"
|
||||||
assert f"Bearer {API_KEY}" in server["headers"]["Authorization"]
|
assert f"Bearer {API_KEY}" in server["headers"]["Authorization"]
|
||||||
|
|
||||||
@pytest.mark.unit
|
@pytest.mark.unit
|
||||||
def test_claude_code_format(self):
|
def test_claude_code_format(self):
|
||||||
"""Claude Code config should use the same mcpServers format."""
|
"""Claude Code config should use the same mcpServers format with http type."""
|
||||||
snippet = generate_config(BASE_URL, USER_ID, ALIAS, API_KEY, "claude_code")
|
snippet = generate_config(BASE_URL, USER_ID, ALIAS, API_KEY, "claude_code")
|
||||||
config = json.loads(snippet)
|
config = json.loads(snippet)
|
||||||
assert "mcpServers" in config
|
assert "mcpServers" in config
|
||||||
server_name = f"mcphub-{ALIAS}"
|
server_name = f"mcphub-{ALIAS}"
|
||||||
assert server_name in config["mcpServers"]
|
assert server_name in config["mcpServers"]
|
||||||
|
assert config["mcpServers"][server_name]["type"] == "http"
|
||||||
|
|
||||||
|
|
||||||
# ── Cursor / VS Code Format ─────────────────────────────────
|
# ── Cursor / VS Code Format ─────────────────────────────────
|
||||||
@@ -80,7 +82,7 @@ class TestCursorVSCodeFormat:
|
|||||||
|
|
||||||
@pytest.mark.unit
|
@pytest.mark.unit
|
||||||
def test_cursor_format(self):
|
def test_cursor_format(self):
|
||||||
"""Cursor config should be valid JSON with mcp.servers."""
|
"""Cursor config should be valid JSON with mcp.servers and http type."""
|
||||||
snippet = generate_config(BASE_URL, USER_ID, ALIAS, API_KEY, "cursor")
|
snippet = generate_config(BASE_URL, USER_ID, ALIAS, API_KEY, "cursor")
|
||||||
config = json.loads(snippet)
|
config = json.loads(snippet)
|
||||||
assert "mcp" in config
|
assert "mcp" in config
|
||||||
@@ -89,15 +91,18 @@ class TestCursorVSCodeFormat:
|
|||||||
assert server_name in config["mcp"]["servers"]
|
assert server_name in config["mcp"]["servers"]
|
||||||
server = config["mcp"]["servers"][server_name]
|
server = config["mcp"]["servers"][server_name]
|
||||||
assert server["url"] == EXPECTED_ENDPOINT
|
assert server["url"] == EXPECTED_ENDPOINT
|
||||||
|
assert server["type"] == "http"
|
||||||
assert f"Bearer {API_KEY}" in server["headers"]["Authorization"]
|
assert f"Bearer {API_KEY}" in server["headers"]["Authorization"]
|
||||||
|
|
||||||
@pytest.mark.unit
|
@pytest.mark.unit
|
||||||
def test_vscode_format(self):
|
def test_vscode_format(self):
|
||||||
"""VS Code config should use the same mcp.servers format as Cursor."""
|
"""VS Code config should use mcp.servers format with http type."""
|
||||||
snippet = generate_config(BASE_URL, USER_ID, ALIAS, API_KEY, "vscode")
|
snippet = generate_config(BASE_URL, USER_ID, ALIAS, API_KEY, "vscode")
|
||||||
config = json.loads(snippet)
|
config = json.loads(snippet)
|
||||||
assert "mcp" in config
|
assert "mcp" in config
|
||||||
assert "servers" in config["mcp"]
|
assert "servers" in config["mcp"]
|
||||||
|
server_name = f"mcphub-{ALIAS}"
|
||||||
|
assert config["mcp"]["servers"][server_name]["type"] == "http"
|
||||||
|
|
||||||
|
|
||||||
# ── ChatGPT Format ───────────────────────────────────────────
|
# ── ChatGPT Format ───────────────────────────────────────────
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# SEO API Bridge - WordPress Plugin
|
# Airano MCP SEO Bridge - WordPress Plugin
|
||||||
|
|
||||||
**Version:** 1.3.0
|
**Version:** 1.3.0
|
||||||
**Requires:** WordPress 5.0+, PHP 7.4+
|
**Requires:** WordPress 5.0+, PHP 7.4+
|
||||||
@@ -72,23 +72,23 @@ SEO API Bridge is a comprehensive WordPress plugin that exposes Rank Math SEO an
|
|||||||
|
|
||||||
### Method 1: Upload via WordPress Admin
|
### Method 1: Upload via WordPress Admin
|
||||||
|
|
||||||
1. Download `seo-api-bridge.zip` from [Releases](https://github.com/airano-ir/mcphub)
|
1. Download `airano-mcp-seo-bridge.zip` from [Releases](https://github.com/airano-ir/mcphub)
|
||||||
2. Go to WordPress Admin > Plugins > Add New > Upload Plugin
|
2. Go to WordPress Admin > Plugins > Add New > Upload Plugin
|
||||||
3. Upload the ZIP file and click "Install Now"
|
3. Upload the ZIP file and click "Install Now"
|
||||||
4. Click "Activate Plugin"
|
4. Click "Activate Plugin"
|
||||||
|
|
||||||
### Method 2: FTP/SSH Upload
|
### Method 2: FTP/SSH Upload
|
||||||
|
|
||||||
1. Upload the `seo-api-bridge` folder to `/wp-content/plugins/`
|
1. Upload the `airano-mcp-seo-bridge` folder to `/wp-content/plugins/`
|
||||||
2. Go to WordPress Admin > Plugins
|
2. Go to WordPress Admin > Plugins
|
||||||
3. Find "SEO API Bridge" and click "Activate"
|
3. Find "Airano MCP SEO Bridge" and click "Activate"
|
||||||
|
|
||||||
### Method 3: WP-CLI
|
### Method 3: WP-CLI
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /var/www/html/wp-content/plugins/
|
cd /var/www/html/wp-content/plugins/
|
||||||
# Copy the plugin folder here
|
# Copy the plugin folder here
|
||||||
wp plugin activate seo-api-bridge
|
wp plugin activate airano-mcp-seo-bridge
|
||||||
```
|
```
|
||||||
|
|
||||||
## REST API Endpoints
|
## REST API Endpoints
|
||||||
@@ -97,10 +97,10 @@ All endpoints require **WordPress Application Password** authentication.
|
|||||||
|
|
||||||
### Status Endpoint
|
### Status Endpoint
|
||||||
|
|
||||||
**GET** `/wp-json/seo-api-bridge/v1/status`
|
**GET** `/wp-json/airano-mcp-seo-bridge/v1/status`
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -X GET "https://yoursite.com/wp-json/seo-api-bridge/v1/status" \
|
curl -X GET "https://yoursite.com/wp-json/airano-mcp-seo-bridge/v1/status" \
|
||||||
-u "username:application_password"
|
-u "username:application_password"
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -121,17 +121,17 @@ curl -X GET "https://yoursite.com/wp-json/seo-api-bridge/v1/status" \
|
|||||||
|
|
||||||
### Post SEO Endpoints
|
### Post SEO Endpoints
|
||||||
|
|
||||||
**GET** `/wp-json/seo-api-bridge/v1/posts/{id}/seo` — Get SEO metadata for a post
|
**GET** `/wp-json/airano-mcp-seo-bridge/v1/posts/{id}/seo` — Get SEO metadata for a post
|
||||||
|
|
||||||
**POST** `/wp-json/seo-api-bridge/v1/posts/{id}/seo` — Update SEO metadata for a post
|
**POST** `/wp-json/airano-mcp-seo-bridge/v1/posts/{id}/seo` — Update SEO metadata for a post
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Get post SEO
|
# Get post SEO
|
||||||
curl -X GET "https://yoursite.com/wp-json/seo-api-bridge/v1/posts/123/seo" \
|
curl -X GET "https://yoursite.com/wp-json/airano-mcp-seo-bridge/v1/posts/123/seo" \
|
||||||
-u "username:application_password"
|
-u "username:application_password"
|
||||||
|
|
||||||
# Update post SEO
|
# Update post SEO
|
||||||
curl -X POST "https://yoursite.com/wp-json/seo-api-bridge/v1/posts/123/seo" \
|
curl -X POST "https://yoursite.com/wp-json/airano-mcp-seo-bridge/v1/posts/123/seo" \
|
||||||
-u "username:application_password" \
|
-u "username:application_password" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{"focus_keyword": "wordpress", "seo_title": "My Title"}'
|
-d '{"focus_keyword": "wordpress", "seo_title": "My Title"}'
|
||||||
@@ -139,18 +139,18 @@ curl -X POST "https://yoursite.com/wp-json/seo-api-bridge/v1/posts/123/seo" \
|
|||||||
|
|
||||||
### Page SEO Endpoints
|
### Page SEO Endpoints
|
||||||
|
|
||||||
**GET** `/wp-json/seo-api-bridge/v1/pages/{id}/seo`
|
**GET** `/wp-json/airano-mcp-seo-bridge/v1/pages/{id}/seo`
|
||||||
|
|
||||||
**POST** `/wp-json/seo-api-bridge/v1/pages/{id}/seo`
|
**POST** `/wp-json/airano-mcp-seo-bridge/v1/pages/{id}/seo`
|
||||||
|
|
||||||
### Product SEO Endpoints (WooCommerce)
|
### Product SEO Endpoints (WooCommerce)
|
||||||
|
|
||||||
**GET** `/wp-json/seo-api-bridge/v1/products/{id}/seo`
|
**GET** `/wp-json/airano-mcp-seo-bridge/v1/products/{id}/seo`
|
||||||
|
|
||||||
**POST** `/wp-json/seo-api-bridge/v1/products/{id}/seo`
|
**POST** `/wp-json/airano-mcp-seo-bridge/v1/products/{id}/seo`
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -X POST "https://yoursite.com/wp-json/seo-api-bridge/v1/products/1217/seo" \
|
curl -X POST "https://yoursite.com/wp-json/airano-mcp-seo-bridge/v1/products/1217/seo" \
|
||||||
-u "username:application_password" \
|
-u "username:application_password" \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{"focus_keyword": "product keyword", "seo_title": "Product Title"}'
|
-d '{"focus_keyword": "product keyword", "seo_title": "Product Title"}'
|
||||||
@@ -223,7 +223,7 @@ result = await mcp.call_tool(
|
|||||||
|
|
||||||
2. **Status Endpoint:**
|
2. **Status Endpoint:**
|
||||||
```bash
|
```bash
|
||||||
curl -X GET "https://your-site.com/wp-json/seo-api-bridge/v1/status" \
|
curl -X GET "https://your-site.com/wp-json/airano-mcp-seo-bridge/v1/status" \
|
||||||
-u "username:application_password"
|
-u "username:application_password"
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -248,7 +248,7 @@ curl -X GET "https://your-site.com/wp-json/wp/v2/posts/1" \
|
|||||||
|
|
||||||
1. Upgrade to v1.1.0+ (has dedicated health check endpoint)
|
1. Upgrade to v1.1.0+ (has dedicated health check endpoint)
|
||||||
2. Restart MCP server
|
2. Restart MCP server
|
||||||
3. Test endpoint: `curl "https://your-site.com/wp-json/seo-api-bridge/v1/status" -u "user:pass"`
|
3. Test endpoint: `curl "https://your-site.com/wp-json/airano-mcp-seo-bridge/v1/status" -u "user:pass"`
|
||||||
|
|
||||||
### SEO Plugin Not Detected
|
### SEO Plugin Not Detected
|
||||||
|
|
||||||
@@ -285,7 +285,7 @@ curl -X GET "https://your-site.com/wp-json/wp/v2/posts/1" \
|
|||||||
- Improved MariaDB compatibility for meta field queries
|
- Improved MariaDB compatibility for meta field queries
|
||||||
|
|
||||||
### 1.1.0 (2025-01-10)
|
### 1.1.0 (2025-01-10)
|
||||||
- Added health check REST API endpoint `/seo-api-bridge/v1/status`
|
- Added health check REST API endpoint `/airano-mcp-seo-bridge/v1/status`
|
||||||
- Direct plugin detection without requiring posts/products
|
- Direct plugin detection without requiring posts/products
|
||||||
- Better compatibility with sites that have no content
|
- Better compatibility with sites that have no content
|
||||||
- Returns SEO plugin versions in status endpoint
|
- Returns SEO plugin versions in status endpoint
|
||||||
|
|||||||
Reference in New Issue
Block a user