WP Manifestindependent plugin directory
manifest / ai / wp-mcp-connector-plugin

WP MCP Connector

Self-contained Model Context Protocol server for WordPress. Streamable HTTP and HTTP+SSE, Application Passwords / bearer tokens / built-in OAuth 2.1, 32 tools, one-call article publishing with images and SEO.

by Remy Mazmanian · github.com/remymazmanian/wp-mcp-connector-plugin · website

0stars
8release downloads
0forks

Install

The author publishes release zips, so WP-CLI can install straight from GitHub:

wp plugin install https://github.com/remymazmanian/wp-mcp-connector-plugin/releases/download/v1.0.1/wp-mcp-connector-1.0.1.zip

Readme

WP MCP Connector

Serve a self-hosted WordPress site to AI clients over the Model Context Protocol.

Claude Desktop, Claude Code, Cursor, Grok and anything else that speaks MCP can read and manage the site through 32 permission-gated tools: posts, pages, media, taxonomies, comments, SEO metadata, plugin and theme inventory, site health, and a set of emulated WP-CLI commands.

  • No Composer. No npm. No build step. The plugin is plain PHP and runs on a stock WordPress install.
  • Two transports. Streamable HTTP (current spec) and HTTP+SSE (legacy clients).
  • Three auth routes. Application Passwords (primary), optional Bearer tokens, and a built-in OAuth 2.1 authorization server with PKCE for hosted clients.
  • One call publishes. wp_publish_article builds a finished post — body, featured image, in-article images at named paragraphs, categories, tags and SEO — in a single tool call.
  • Modern where it counts. On WordPress 6.9+ every tool is also registered with the core Abilities API, so the same definitions are reachable from /wp-json/wp-abilities/v1/ and from the official MCP Adapter if you install it. On 7.1+ each ability also carries the unified public exposure flag that core, the MCP Adapter and AI agents read.

Contents

  1. Architecture
  2. Requirements
  3. Install and activate
  4. Configure
  5. Generate an Application Password
  6. Credential storage
  7. Connect a client
  8. The stdio bridge
  9. Tool reference
  10. Security model
  11. Example prompts
  12. Troubleshooting
  13. Extending

Architecture

Claude Desktop / Claude Code / Cursor / Grok
        │
        ├─ (A) native remote MCP ──► POST /wp-json/mcp/v1/mcp     Streamable HTTP
        ├─ (B) legacy clients ─────► GET  /wp-json/mcp/v1/sse      HTTP+SSE
        └─ (C) stdio-only clients ─► npx wp-mcp-bridge ──► (A)     zero-dep TS proxy
                                              │
                          ┌───────────────────┴──────────────────┐
                          │  WPMCP_Server  (JSON-RPC 2.0 engine) │
                          │  initialize / tools.list / tools.call │
                          └───────────────────┬──────────────────┘
              ┌──────────────┬────────────────┼──────────────┬─────────────┐
           Auth          Rate limiter     Registry        Abilities     Logger
      (App Password    (sliding window   (32 tools,       mirror →
       + Bearer         per user)         cap-gated)      WP core Abilities API
       + OAuth 2.1)

The protocol engine is transport agnostic. Streamable HTTP and legacy SSE both hand messages to the same WPMCP_Server, and differ only in how they frame the reply, so behaviour cannot drift between them.

Why a self-contained server rather than only the MCP Adapter

The official wordpress/mcp-adapter package is the direction of travel, but it needs Composer and a feature plugin, and its API has moved between releases. This plugin therefore does both:

Self-contained endpoints Abilities API mirror
Requires nothing WordPress 6.9+
Endpoint /wp-json/mcp/v1/mcp /wp-json/wp-abilities/v1/abilities/…/run
Always available yes when core supports it
Used by MCP Adapter no yes, if installed

One tool definition feeds all three paths. Adding a tool once exposes it everywhere.

File layout

wp-mcp-connector/
├── wp-mcp-connector.php              bootstrap, constants, autoloader
├── includes/
│   ├── class-wpmcp-plugin.php        orchestrator, tool registry owner
│   ├── class-wpmcp-server.php        JSON-RPC 2.0 / MCP protocol engine
│   ├── class-wpmcp-rest.php          Streamable HTTP + legacy SSE transports
│   ├── class-wpmcp-auth.php          Application Passwords + Bearer tokens
│   ├── class-wpmcp-settings.php      settings, permission profiles
│   ├── class-wpmcp-registry.php      tool registry and exposure rules
│   ├── class-wpmcp-schema.php        JSON Schema builders and validator
│   ├── class-wpmcp-session.php       MCP sessions + legacy SSE message queue
│   ├── class-wpmcp-rate-limiter.php  per-user sliding window
│   ├── class-wpmcp-logger.php        rolling activity log
│   ├── class-wpmcp-seo.php           SEO adapter (Yoast / Rank Math / SEOPress / custom)
│   ├── class-wpmcp-abilities.php     core Abilities API mirror + MCP Adapter handoff
│   ├── class-wpmcp-admin.php         settings screen
│   └── tools/
│       ├── class-wpmcp-tools-content.php
│       ├── class-wpmcp-tools-taxonomy.php
│       ├── class-wpmcp-tools-media.php
│       ├── class-wpmcp-tools-site.php
│       ├── class-wpmcp-tools-comments.php
│       └── class-wpmcp-tools-maintenance.php
└── bridge/                           optional TypeScript stdio bridge
    ├── package.json
    ├── tsconfig.json
    └── src/index.ts

Requirements

Minimum Notes
WordPress 6.4 6.9+ additionally registers abilities in core; tested up to 7.1
PHP 7.4 tested on 8.2 and 8.4
HTTPS required in production local environments are exempt
Composer not needed
npm only for the optional bridge Node 18+

Install and activate

A short connection walkthrough for Grok, ChatGPT and Claude lives at remymazmanian.com/connect-grok-chatgpt-claude-to-wordpress.

Upload the folder:

rsync -av wp-mcp-connector/ user@host:/path/to/wp-content/plugins/wp-mcp-connector/

Or zip it and use Plugins → Add New → Upload Plugin.

Activate, then open Settings → MCP Connector.

The server ships switched off and on the least-privileged profile. Nothing is reachable until you enable it.

Verify it is running

curl -u 'USERNAME:APP_PASSWORD' https://example.com/wp-json/mcp/v1/health

A healthy response reports the WordPress and PHP versions, which auth method was used, the active profile, and the exact list of tools that user can currently call.


Configure

Settings → MCP Connector.

Permission profiles

A profile decides which tools are offered. The connected WordPress user still needs the matching capability, so a profile can never grant more than the account already has.

Profile Tools Use for
Read only 12 research, audits, reporting
Author 25 drafting and editing content, uploading media
Editor 29 the above plus trashing content and moderating comments
Administrator 32 everything, including permanent deletion and option writes
Custom your choice tick exactly the tools you want

The default is Author: it can create and update content but cannot delete anything, cannot touch options, and cannot run the CLI emulator.

Other settings worth setting deliberately

  • Required capability — the floor for reaching the endpoints at all. Default edit_posts.
  • Rate limit — default 120 tool calls per 60 seconds per user. An agent stuck in a retry loop hits this instead of your database.
  • Readable and writable options — an allowlist. wp_get_option and wp_update_option refuse everything not on it, and the refusal names what is allowed.
  • Media download hosts — leave empty to allow any public host. Private and loopback addresses are always blocked regardless.
  • Legacy SSE transport — each open stream holds a PHP worker for the configured duration. Turn it off unless a client needs it.

Generate an Application Password

Application Passwords are built into WordPress and are the recommended credential. They are per-application, revocable individually, and never expose the account's real password.

  1. Users → Profile (or Users → All Users → edit the user).
  2. Scroll to Application Passwords.
  3. Enter a name that identifies the client, for example Claude Desktop, work laptop.
  4. Click Add New Application Password.
  5. Copy the value shown. It looks like abcd EFGH ijkl MNOP qrst UVWX and is displayed once only.

The spaces are cosmetic and WordPress ignores them. Use it as the HTTP Basic password with the account's username (not email):

curl -u 'remy:abcdEFGHijklMNOPqrstUVWX' https://example.com/wp-json/mcp/v1/health

Create a dedicated account for this. An account with the Author or Editor role, used only by the AI client, means a leaked credential cannot install plugins or read user emails, and revoking it does not disturb your own login.

If the Application Passwords section is missing: WordPress hides it when the request is not over HTTPS and the environment type is not local. Fix the HTTPS, or set WP_ENVIRONMENT_TYPE to local in wp-config.php for local development.

Bearer tokens (optional)

Required for hosted clients such as Grok, and useful for any client you want to hold on a shorter leash. Enable Bearer tokens in settings, then issue one at the bottom of the settings page: pick a user, a label, a scope and an expiry. The token is shown once and only a SHA-256 hash is stored.

Bearer tokens work on /wp-json/mcp/v1/* and nowhere else. That is deliberate, and it is the main reason to prefer them for anything you do not control: a token that also unlocked the whole REST API, including plugin installation and every ability registered by every other plugin, would be a far larger credential than the job needs. See Connecting an administrator account safely.


Credential storage

What an Application Password is and is not

It is not your WordPress password. It is a separate 24-character credential that cannot be used at wp-login.php, does not reveal your real password, and can be revoked on its own without disturbing your login or any other client.

But be clear about what it can do. An Application Password authenticates against the whole REST API, not just this plugin's endpoints. If it belongs to an administrator, it can reach /wp/v2/plugins to install and activate plugins, /wp/v2/users to read every account's email address, and /wp/v2/users/me/application-passwords to mint more credentials — none of which this plugin's permission profiles constrain, because those routes are WordPress core's, not ours.

So the single most effective thing you can do is not use an administrator account. An Editor-role Application Password cannot touch /wp/v2/plugins at all: the capability check fails before your configuration is even consulted. Every tool in the Editor profile still works.

Account role Worst case if the credential leaks
Administrator Full site compromise: plugin installation, user data, new credentials
Editor Content and comments can be altered; no code execution, no user emails
Author Its own drafts can be altered

Where the secret ends up

Ordinary MCP client setup writes the credential to disk in plaintext:

Client File Format
Claude Code (--scope user) ~/.claude.json plaintext JSON
Claude Code (--scope project) .mcp.json plaintext JSON, easy to commit by accident
Claude Desktop claude_desktop_config.json plaintext JSON
Cursor ~/.cursor/mcp.json plaintext JSON

A claude mcp add … --header "Authorization: Basic $(…)" command also lands in your shell history.

Keychain-backed credentials (macOS)

The bridge can keep the secret in the login keychain instead, so no config file and no shell history ever contains it. Store it once:

node bridge/dist/index.js --save-credential \
  --url https://example.com/wp-json/mcp/v1/mcp \
  --user YOUR_USERNAME

security is spawned with the terminal attached and does its own no-echo, type-it-twice prompt. The secret therefore never passes through argv (where ps could see it), the environment, a Node string, or your history — it goes straight from your keyboard into the keychain.

From then on the client config holds only non-secret values:

{
  "mcpServers": {
    "wordpress": {
      "command": "node",
      "args": ["/absolute/path/to/bridge/dist/index.js"],
      "env": {
        "WP_MCP_URL": "https://example.com/wp-json/mcp/v1/mcp",
        "WP_MCP_USERNAME": "YOUR_USERNAME"
      }
    }
  }
}

Verify, and remove, with:

node bridge/dist/index.js --probe --url https://example.com --user YOUR_USERNAME
node bridge/dist/index.js --delete-credential --url https://example.com --user YOUR_USERNAME

Credentials are stored under the service name wp-mcp-bridge, keyed by username@host, so one machine can hold several sites and several users without collision. They are visible and revocable in Keychain Access. An explicit WP_MCP_APP_PASSWORD or WP_MCP_TOKEN still wins when set, so CI and existing setups are unaffected.

On Linux and Windows the keychain flags are refused with an explanation; use environment variables from your OS credential store there.

Keeping the secret out of shell history

If you do use the header approach, avoid pasting the credential on a command line:

read -rs -p 'App password: ' APW
claude mcp add --scope user --transport http wordpress \
  https://example.com/wp-json/mcp/v1/mcp \
  --header "Authorization: Basic $(printf '%s' "USERNAME:$APW" | base64)"
unset APW

read -rs does not echo and does not record. The credential still lands in ~/.claude.json, so this is a partial measure — the keychain route above is the one that removes it entirely.


Connect a client

Endpoint: https://example.com/wp-json/mcp/v1/mcp

Read the full README on GitHub →

Releases

TagPublishedAssetDownloads
v1.0.1 Aug 19, 2026 wp-mcp-connector-1.0.1.zip 8