WordPress MCP (Modern)
Modern WordPress MCP server on the official mcp-adapter + Abilities API — 63 tools, 5 resources, 2 prompts, JWT + Application Password auth, HTTP & STDIO transports.
by consigcody94 · github.com/consigcody94/wordpress-mcp-modern
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/consigcody94/wordpress-mcp-modern/archive/refs/heads/main.zipReadme
🤖 WordPress MCP (Modern)
Turn any WordPress site into a first-class Model Context Protocol server — built the modern way, on the WordPress Abilities API.
| 🔧 82 tools | 📚 5 resources | 💬 2 prompts | 🔐 3 auth methods | 🔌 2 transports | 🛒 WooCommerce-aware |
|---|
Quick start · Connect a client · Tools · Security · Extend it · FAQ
✨ What is this?
This plugin makes your WordPress site directly usable by AI assistants. Once installed, tools like Claude Desktop, Cursor, or VS Code Copilot can securely read and manage your content — posts, pages, media, users, taxonomies, settings, even your WooCommerce store — by talking to your site over the open Model Context Protocol (MCP).
In practice, that means conversations like these just work:
| 💬 You ask your AI… | ⚡ …and it calls |
|---|---|
| "Draft a post announcing the spring sale and publish it." | wp_add_post |
| "What are my five most recent draft pages?" | wp_pages_search |
| "Upload this logo to the media library with proper alt text." | wp_upload_media |
| "How did the store do last month?" | wc_reports_sales |
| "Create a 'Tutorials' category and file the latest posts under it." | wp_add_category + wp_update_post |
Everything runs under your WordPress permissions — the AI can never do anything the authenticated user couldn't already do, and you can gate or disable any tool from a settings page.
🆕 New to MCP? A 60-second primerThe Model Context Protocol is an open standard (think "USB-C for AI") that lets AI applications discover and call capabilities exposed by servers. An MCP server offers three kinds of things:
- Tools — actions the AI can take (create a post, search users, upload media).
- Resources — data the AI can read for context (site info, active theme, settings).
- Prompts — reusable, server-defined instruction templates ("analyze my sales").
Your WordPress site becomes one of those servers. Any MCP-compatible client — Claude Desktop, Cursor, VS Code, or your own agent — can connect to it, see what it offers, and use it. The protocol handles discovery, schemas, and transport; this plugin supplies the WordPress capabilities.
💡 Why this exists
The original Automattic/wordpress-mcp is deprecated. Its successor is the official WordPress/mcp-adapter AI Building Block, which sits on top of the new Abilities API shipping in WordPress Core 6.9.
This project is a ground-up re-implementation of the old plugin's capabilities on that modern stack:
| Old way (deprecated) | Modern way (this plugin) | |
|---|---|---|
| Capabilities | Bespoke Mcp*Tools PHP classes |
Every capability is a WordPress Ability |
| Transport | Hand-rolled | The official mcp-adapter transport |
| Reusability | Tightly coupled to MCP | Abilities are reusable by any AI building block |
| Shape | Monolithic plugin | Thin plugin + Composer dependency |
[!TIP] The big idea: you don't register "tools" — you register Abilities (
wp_register_ability()), and mcp-adapter exposes them as MCP tools, resources, and prompts. Same capability, many surfaces. When the next AI surface arrives in WordPress, your abilities come along for free.
🏛️ Architecture at a glance
flowchart LR
Client["🧠 AI Client<br/>(Claude, Cursor, VS Code…)"]
subgraph WP["🌐 WordPress 6.9+ / PHP 8.0+"]
direction TB
Perm["🔐 TransportPermission<br/>JWT · App Password"]
Server["🗂️ MCP Server<br/>/wp-json/wpmcp/mcp"]
Reg["📇 AbilityRegistrar<br/>(gating · name mapping)"]
Abilities[("⚡ WordPress Abilities")]
Core["WP REST API · core functions · WooCommerce"]
Perm --> Server --> Reg --> Abilities --> Core
end
Client -->|"HTTP (Streamable) or STDIO"| Perm
mcp["📦 wordpress/mcp-adapter<br/>(Composer)"] -.bridges.-> Server
Each piece has one job:
TransportPermission— the front door. Validates the JWT or relies on WordPress's own Application Password auth, then establishes the WordPress user for the request.- MCP Server (from
wordpress/mcp-adapter) — speaks the MCP protocol: discovery, sessions, schemas, content blocks. This plugin never parses MCP itself. AbilityRegistrar— the single source of truth for what's exposed. Applies your gating settings and maps modern ability names back to the legacy tool names clients already know.- Abilities — the actual capabilities, registered via the core Abilities API and mostly executing through the real WordPress REST API.
🚀 Quick start
[!IMPORTANT] Requirements: WordPress 6.9+ (ships the Abilities API) and PHP 8.0+.
Step 1 — Install the plugin
From a release (easiest — no Composer needed): grab wordpress-mcp-modern.zip from the Releases page — it bundles all PHP dependencies — and install it via Plugins → Add New → Upload Plugin.
From source:
cd wp-content/plugins/
git clone https://github.com/consigcody94/wordpress-mcp-modern.git
cd wordpress-mcp-modern
composer install --no-dev
wp plugin activate wordpress-mcp-modern
Your MCP endpoint is now live at /wp-json/wpmcp/mcp. 🎉
Step 2 — Create credentials
The fastest path is an Application Password: go to Users → Profile → Application Passwords, name it (e.g. mcp), and copy the generated password. That's it — no plugin configuration needed. (Prefer revocable tokens? See Authentication for JWTs.)
Step 3 — Connect your AI client
The server supports HTTP (Streamable) and STDIO transports. Pick your client:
🖥️ Claude Desktop / Cursor — via the official proxy + Application PasswordAdd this to your client's MCP config (e.g. claude_desktop_config.json):
{
"mcpServers": {
"wordpress": {
"command": "npx",
"args": ["-y", "@automattic/mcp-wordpress-remote@latest"],
"env": {
"WP_API_URL": "https://your-site.com/wp-json/wpmcp/mcp",
"WP_API_USERNAME": "your-username",
"WP_API_PASSWORD": "xxxx xxxx xxxx xxxx xxxx xxxx"
}
}
}
}
The proxy bridges the client's STDIO transport to your site's HTTP endpoint and handles Basic auth for you.
📝 VS Code — direct HTTP transport with a JWT{
"servers": {
"wordpress": {
"type": "http",
"url": "https://your-site.com/wp-json/wpmcp/mcp",
"headers": { "Authorization": "Bearer <your-jwt>" }
}
}
}
⌨️ STDIO via WP-CLI (local / same machine)
wp mcp-adapter serve --server=wpmcp-modern --user=admin
Step 4 — Verify it works
🧪 Kick the tires with curl# initialize → grab the Mcp-Session-Id response header, then send it back on every call
curl -i -u "admin:APP_PASSWORD" -X POST https://your-site.com/wp-json/wpmcp/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Mcp-Protocol-Version: 2025-06-18" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize",
"params":{"protocolVersion":"2025-06-18","capabilities":{},
"clientInfo":{"name":"curl","version":"0"}}}'
Or simply ask your connected AI: "What WordPress tools do you have?" — it should list the toolset below.
🔐 Authentication
Three interchangeable mechanisms, enforced by the server's transport-permission callback. Use whichever fits:
| 🔑 Application Passwords | 🎫 JWT | 🌐 OAuth 2.1 (experimental) | |
|---|---|---|---|
| Setup | None — built into WordPress | Issue via REST route or admin UI | Enable the toggle; clients self-register |
| Format | HTTP Basic auth | Authorization: Bearer <jwt> |
Bearer token (a plugin JWT under the hood) |
| Lifetime | Until you delete it | 1 hour by default, up to 30 days | 1 day by default (filterable) |
| Revocation | Delete from your profile | Instant, per-token (jti) — independent of expiry |
Same as JWT — same registry |
| Best for | Personal use, the proxy setup | Short-lived agents, CI, shared automations | Clients with built-in OAuth flows — no token pasting |
Application Passwords (recommended start)
Standard WordPress HTTP Basic auth — zero extra setup. Create one under Users → Profile → Application Passwords.
JWT
Stateful, revocable HS256 tokens with a full management API:
| Route | Method | Who | Purpose |
|---|---|---|---|
/wp-json/jwt-auth/v1/token |
POST |
anyone | Issue a token (current user, or username/password; optional expires_in) |
/wp-json/jwt-auth/v1/tokens |
GET |
admin | List active tokens |
/wp-json/jwt-auth/v1/revoke |
POST |
admin | Revoke by jti |
Tokens default to a 1-hour lifetime; you can request up to 30 days via expires_in (the ceiling is filterable through wpmcp_jwt_max_expiration_time). Configure the signing secret with a constant in wp-config.php (otherwise one is auto-generated and stored):
define( 'WPMCP_JWT_SECRET_KEY', 'a-long-random-string' );
[!NOTE] 🛡️ Tokens are stateful — every token is recorded server-side, so revocation works immediately and independently of expiry. (The legacy plugin documented
WPMCP_JWT_SECRET_KEYbut never read it; here it's honoured.)
You can also generate, list, and revoke tokens visually from Settings → WordPress MCP.
OAuth 2.1 (experimental, opt-in)
Turn on OAuth 2.1 authorization in Settings → WordPress MCP and OAuth-capable MCP clients can connect with zero token copy-pasting. The plugin implements the slice of the MCP authorization spec clients exercise:
- Discovery —
/.well-known/oauth-authorization-serverand/.well-known/oauth-protected-resource(RFC 8414/9728; no rewrite rules needed). - Dynamic client registration —
POST /wp-json/wpmcp/v1/oauth/register(RFC 7591, public clients). - Authorization code + PKCE (S256 only) — a WordPress consent screen asks the logged-in user to approve the client.
- Token exchange —
POST /wp-json/wpmcp/v1/oauth/tokenreturns a plugin JWT, so OAuth tokens are validated, listed, and revoked through the exact same machinery as manually issued ones.
[!NOTE] No refresh tokens yet — access tokens default to 1 day (
wpmcp_oauth_token_expirationfilter), after which the client re-runs the (one-click) consent flow.
🧰 What's exposed
82 tools (54 always-on + 28 WooCommerce when active), 5 resources, 2 prompts. Legacy tool names (wp_posts_search, wc_get_product, …) are preserved, so existing clients and prompts keep working.
🔧 Tools
| Group | Count | Examples |
|---|---|---|
| 📝 Posts | 5 | wp_posts_search, wp_get_post, wp_add_post, wp_update_post, wp_delete_post |
| 📄 Pages | 5 | wp_pages_search, wp_add_page, wp_update_page, … |
| 🏷️ Taxonomy | 8 | wp_list_categories, wp_add_category, wp_list_tags, wp_add_tag, … |
| 👤 Users | 7 | wp_users_search, wp_add_user, wp_get_current_user, … |
| ⚙️ Settings | 2 | wp_get_general_settings, wp_update_general_settings |
| 🧩 Custom post types | 6 | wp_list_post_types, wp_cpt_search, wp_add_cpt, … |
| 🖼️ Media | 7 | wp_list_media, wp_upload_media (base64 in), wp_get_media_file (URL · base64 · image/blob content blocks), … |
| 💬 Comments | 6 | wp_comments_search, wp_add_comment (reply via parent), wp_moderate_comment, … |
| 🔌 Plugins & themes | 5 | wp_list_plugins, wp_activate_plugin, wp_deactivate_plugin (never itself), wp_activate_theme, … |
| 🧭 Core (reused) | 3 | get_site_info, get_user_info, get_environment_info |
| 🛒 WooCommerce* | 28 | wc_products_search, wc_add_product, wc_list_product_brands, wc_add_order, wc_reports_sales, … |
| 🧪 Generic (REST-CRUD mode) | 3 | list_api_functions, get_function_details, run_api_function |
*WooCommerce tools register only when WooCommerce is active. The generic REST-CRUD tools appear only in REST-CRUD mode (see Security & gating).