Install
$ agentstack add mcp-jeanmarieclement-wp-ai-bridge ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README — it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming — see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps — measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
WP AI Bridge
[](https://github.com/jeanmarieclement/wp-ai-bridge/releases) [](https://github.com/jeanmarieclement/wp-ai-bridge/actions) [](https://wordpress.org) [](https://php.net) [](LICENSE)
A WordPress plugin that exposes secure REST endpoints for content management via per-user API keys or OAuth2 (Authorization Code flow). Designed for integration with external AI services (Claude.ai, ChatGPT, custom automations).
Version: 1.5.0 Compatibility: WordPress 6.0+, PHP 7.4+ License: MIT
What It Does
Exposes a REST API under the /wp-json/wpaib/v1/ namespace for:
- Listing, creating, reading, updating, and deleting posts and pages
- Custom Post Types — discover and CRUD any registered CPT (WooCommerce products, portfolios, events, reviews…) via
/cpt - Uploading images (base64) to the media library
- Listing and creating categories and tags
- Reading site info and full-text search (includes CPTs)
- Managing plugins — list, activate, deactivate, delete (
/plugins, admin-only) - Managing updates — check and apply core, plugin, and theme updates (
/updates, admin-only) - MCP/function-calling tool execution (
/tools,/tools/execute) - Dynamic OpenAPI 3.0.3 schema (
/openapi.json) — import-ready for ChatGPT, Gemini, Claude.ai
Two authentication methods are supported and can be used interchangeably on any endpoint:
| Method | Header | Use when | |--------|--------|----------| | API Key | X-API-Key: wpaib_... | Scripts, automations, direct integrations | | OAuth2 Bearer | Authorization: Bearer wpaib_at_... | ChatGPT Custom Actions, Claude.ai tools, user-facing flows |
Installation
- Upload the
wp-ai-bridgefolder towp-content/plugins/ - Go to WordPress → Plugins and activate "WP AI Bridge"
> Troubleshooting: If OAuth2 endpoints (/authorize, /token) or the MCP endpoint return 404 after installation or update, go to Settings → Permalinks and click Save Changes to flush WordPress rewrite rules.
Authentication — API Key
- Go to Users → Profile (or edit any user as admin)
- Scroll down to "WP AI Bridge — API Keys"
- Enter a label (e.g.
Home laptop) and click Generate key - Copy the key immediately — it will not be shown again
curl https://your-site.com/wp-json/wpaib/v1/posts \
-H "X-API-Key: wpaib_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Authentication — OAuth2
WP AI Bridge acts as an OAuth2 Authorization Server (Authorization Code flow). Use this when connecting via ChatGPT Custom Actions, Claude.ai tools, or any OAuth2-capable client.
Setup
- Go to Settings → WP AI Bridge → OAuth2 Clients
- Click Aggiungi client, enter a name and the redirect URI(s) provided by the platform
- Copy the
client_idandclient_secretshown immediately (secret not shown again)
Endpoints
| Role | URL | |------|-----| | Authorization | https://your-site.com/wpaib/oauth/authorize | | Token | https://your-site.com/wp-json/wpaib/v1/oauth/token | | Revoke | https://your-site.com/wp-json/wpaib/v1/oauth/revoke | | OpenAPI schema | https://your-site.com/wp-json/wpaib/v1/openapi.json |
Redirect URIs by platform
| Platform | Redirect URI | |----------|-------------| | ChatGPT Custom Actions | https://chat.openai.com/aip/g-/oauth/callback | | Claude.ai tools | https://claude.ai/api/oauth/callback |
Flow summary
Client → GET /wpaib/oauth/authorize?response_type=code&client_id=...&redirect_uri=...&state=...
← WordPress login (if not logged in)
← Consent page (Autorizza / Nega)
→ POST /wpaib/oauth/authorize (user clicks Autorizza)
← redirect_uri?code=wpaib_ac_...&state=...
Client → POST /wp-json/wpaib/v1/oauth/token
grant_type=authorization_code&code=...&client_id=...&client_secret=...&redirect_uri=...
← { "access_token": "wpaib_at_...", "refresh_token": "wpaib_rt_...", "token_type": "Bearer", "expires_in": 3600 }
Client → GET /wp-json/wpaib/v1/posts
Authorization: Bearer wpaib_at_...
← posts JSON
Token lifetimes
| Token | Lifetime | |-------|---------| | Authorization code | 10 minutes (one-shot) | | Access token | 1 hour | | Refresh token | 30 days (rotated on each use) |
Token refresh
curl -X POST https://your-site.com/wp-json/wpaib/v1/oauth/token \
-d "grant_type=refresh_token&refresh_token=wpaib_rt_...&client_id=...&client_secret=..."
Token revoke
curl -X POST https://your-site.com/wp-json/wpaib/v1/oauth/revoke \
-d "token=wpaib_at_...&client_id=...&client_secret=..."
Returns {} with 200 even if the token did not exist (RFC 7009).
Security Architecture
Every REST request passes these cascading checks:
| # | Check | What it does | |---|-------|-------------| | 1 | HTTPS check | Rejects plain HTTP (bypassed for localhost/dev) | | 2 | Rate limiter | Max 300 requests/min per key/token | | 3 | Auth — Bearer | Validates OAuth2 access token: hash lookup + expiry + revocation | | 3 | Auth — API Key | SHA-256 hash against DB, regex format pre-check | | 4 | WordPress capability | Verifies edit_posts on the user linked to the credential | | 5 | Input sanitization | sanitize_* + wp_kses_post on all data |
OAuth2 security properties:
- Authorization codes are one-shot (invalidated immediately after use)
- Client secrets stored as SHA-256 hashes only
- Access and refresh tokens stored as SHA-256 hashes only
- Refresh token rotation on every use
redirect_urivalidated against pre-registered list on both GET and POST- CSRF protection via WP nonce on consent form
- Cross-client revoke prevention:
revoke_tokenvalidates client ownership
Audit log: every access (success, auth failure, rate limit, forbidden) is logged to wp_wpaib_audit_log with timestamp, IP, user-agent, endpoint, and outcome.
What the plugin does NOT do (by design):
- Does not expose endpoints to manage users, roles, or options
- Plugin, theme, and update management require the matching WordPress capability (
activate_plugins,delete_plugins,update_plugins,update_themes,update_core) on the credential's user — administrators only - Does not allow arbitrary code execution
- Does not serve files from the server
- Does not trust proxy headers unless explicitly configured
API Examples
Both auth methods work on all endpoints.
Create a draft post (API key)
curl -X POST https://your-site.com/wp-json/wpaib/v1/posts \
-H "Content-Type: application/json" \
-H "X-API-Key: wpaib_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-d '{
"title": "My test post",
"content": "HTML content of the post.",
"excerpt": "Short summary",
"status": "draft",
"categories": [5],
"tags": ["ai", "wordpress", "automation"]
}'
Create a draft post (OAuth2 Bearer)
curl -X POST https://your-site.com/wp-json/wpaib/v1/posts \
-H "Content-Type: application/json" \
-H "Authorization: Bearer wpaib_at_xxxxxxxx..." \
-d '{ "title": "Post via OAuth2", "status": "draft" }'
Upload an image (base64)
curl -X POST https://your-site.com/wp-json/wpaib/v1/media \
-H "Content-Type: application/json" \
-H "X-API-Key: wpaib_xxxx..." \
-d '{
"filename": "cover.png",
"image_base64": "iVBORw0KGgoAAAANS..."
}'
List categories
curl https://your-site.com/wp-json/wpaib/v1/categories \
-H "X-API-Key: wpaib_xxxx..."
Python example
import requests, base64
API_BASE = "https://your-site.com/wp-json/wpaib/v1"
HEADERS = {"X-API-Key": "wpaib_xxxx...", "Content-Type": "application/json"}
# 1. Upload featured image
with open("cover.png", "rb") as f:
b64 = base64.b64encode(f.read()).decode()
media = requests.post(f"{API_BASE}/media", headers=HEADERS, json={
"filename": "cover.png",
"image_base64": b64,
}).json()
# 2. Create draft with featured image
post = requests.post(f"{API_BASE}/posts", headers=HEADERS, json={
"title": "Post from my script",
"content": "Content.",
"status": "draft",
"featured_media": media["id"],
"tags": ["automation"],
}).json()
print(f"Draft created: {post['link']}")
Custom Post Types
# 1. Discover available CPTs
curl https://your-site.com/wp-json/wpaib/v1/cpt \
-H "X-API-Key: wpaib_xxxx..."
# → { "items": [ {"slug": "review", "name": "Reviews", ...}, {"slug": "product", ...} ], "total": 2 }
# 2. List items of a CPT
curl https://your-site.com/wp-json/wpaib/v1/cpt/review?status=publish&per_page=5 \
-H "X-API-Key: wpaib_xxxx..."
# 3. Create a new CPT item
curl -X POST https://your-site.com/wp-json/wpaib/v1/cpt/review \
-H "Content-Type: application/json" \
-H "X-API-Key: wpaib_xxxx..." \
-d '{
"title": "Great product",
"content": "Highly recommended!",
"status": "publish",
"taxonomies": { "review_category": ["electronics"], "review_tag": [3, 7] }
}'
# 4. Update a CPT item
curl -X PUT https://your-site.com/wp-json/wpaib/v1/cpt/review/42 \
-H "Content-Type: application/json" \
-H "X-API-Key: wpaib_xxxx..." \
-d '{ "status": "draft" }'
# 5. Delete a CPT item
curl -X DELETE https://your-site.com/wp-json/wpaib/v1/cpt/review/42?force=true \
-H "X-API-Key: wpaib_xxxx..."
> Note: Only CPTs registered with public = true and show_in_rest = true are exposed. Built-in types (post, page, attachment) are excluded — use the dedicated /posts and /pages endpoints instead.
Response Codes
| Code | Meaning | |------|---------| | 200 | OK | | 201 | Resource created | | 400 | Invalid body or missing parameters | | 401 | Missing or invalid credential (API key or Bearer token) | | 403 | Insufficient capability or HTTPS required | | 404 | Resource not found | | 413 | File too large | | 429 | Rate limit exceeded | | 500 | Server error |
For security reasons, 401 errors do not distinguish between missing, invalid, expired, or revoked credentials (anti-enumeration).
Advanced Configuration (wp-config.php)
// Only if your site is behind a TRUSTED reverse proxy/CDN (Cloudflare, etc.)
// and you want the logged IP to be the real client IP.
define( 'WPAIB_TRUST_PROXY', true );
Do not enable WPAIB_TRUST_PROXY if the site is exposed directly: X-Forwarded-For headers are spoofable.
Post-Installation Hardening Checklist
The plugin does its part, but security is a chain. Also verify:
- [ ] Valid HTTPS enforced site-wide (Let's Encrypt, HSTS active)
- [ ] WordPress, plugins, and theme always up to date
- [ ] Strong admin passwords + 2FA on high-capability accounts
- [ ] Security plugin active (Wordfence, Solid Security, etc.)
- [ ] Automated daily off-site backups (UpdraftPlus, BackWPup)
- [ ] Login attempt limiting (brute-force protection)
- [ ]
wp-config.phppermissions set to 600 - [ ] XML-RPC disabled if unused
- [ ] Monitor
wp_wpaib_audit_logperiodically - [ ] Revoke API keys and OAuth2 clients that are no longer in use
- [ ] Rotate OAuth2 client secrets periodically
Database Tables
| Table | Purpose | |-------|---------| | wp_wpaib_api_keys | Per-user API keys (SHA-256 hash, label, timestamps) | | wp_wpaib_audit_log | Audit log of all API requests | | wp_wpaib_oauth_clients | Registered OAuth2 clients (name, secret hash, redirect URIs) | | wp_wpaib_oauth_codes | Authorization codes (one-shot, 10-min TTL) | | wp_wpaib_oauth_tokens | Access + refresh token pairs (hash, expiry, revocation) |
Uninstallation
Deactivating the plugin leaves data in the database. To remove everything (keys, OAuth2 clients, tokens, logs, options), use Delete from the Plugins page: the uninstall.php script will clean up everything.
Known Limitations
- No at-rest encryption for audit logs (log queries are in plaintext in the DB, but contain no sensitive data)
- Rate limiter uses WordPress transients: benefits automatically from an external object cache (Redis/Memcached), otherwise falls back to DB
- Upload limited to 5 MB; supported types: jpg, png, gif, webp
- OAuth2 token endpoint does not yet appear in the Connections audit log tab
Contributing
See [CONTRIBUTORS.md](CONTRIBUTORS.md).
License
This project is licensed under the [MIT License](LICENSE).
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: jeanmarieclement
- Source: jeanmarieclement/wp-ai-bridge
- License: MIT
- Homepage: https://github.com/jeanmarieclement/wp-ai-bridge
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.