Connect Claude Code to WordPress MCP with the Official MCP Adapter

To connect Claude Code to WordPress over MCP, install the official MCP Adapter plugin (version 0.7.1) from the WordPress.org directory. Then point Claude Code, Cursor or VS Code at the default server at /wp-json/mcp/mcp-adapter-default-server. On a local site, the client runs WP-CLI over STDIO. On a live site, it goes through the @automattic/mcp-wordpress-remote proxy with an Application Password.
The AI reaches your site's abilities through three built-in tools. To give it something of your own to call, register an ability with wp_register_ability() and mark it public.
- What MCP Adapter is (and isn't)
- Install the official plugin
- How the default server works
- Option A: local site over STDIO
- Option B: live site over HTTP
- Add your own read-only ability
- How the ability works and how to test it
- Troubleshooting
- Security checklist
What MCP Adapter is (and isn't)
MCP Adapter is the server and transport layer between WordPress and MCP clients. It takes abilities registered with the Abilities API, in core since WordPress 6.9, and makes them callable from Claude Code, Claude Desktop, Cursor, VS Code and other MCP clients. It has no AI features, no MCP client and no chat UI of its own. If your site exposes no abilities, the AI has nothing to call.
Current facts for version 0.7.1, released 15 October 2026:
- Requires WordPress 6.9 or higher and PHP 7.4 or higher. Tested up to WordPress 7.1.3.
- Supports MCP revisions 2025-11-25 and 2026-07-28. Clients that ask for 2025-06-18 or 2024-11-05 still connect and are served with the 2025-11-25 schema.
- The standalone Abilities API plugin has not been supported since 0.6.0. Use the API in core instead.
- The plugin is still experimental and pre-1.0. MCP stays out of core because the spec is still changing, and the 2026-07-28 revision was a major breaking update.
The WordPress Core AI team released it as a canonical plugin on WordPress.org on 7 October 2026. If you follow Claude Code news, see also our piece on the Claude Code source code leak.
Install the official plugin
Install the plugin from the WordPress.org directory, not from a GitHub ZIP or a copy bundled inside another plugin.
- In WP Admin, go to Plugins > Add New.
- Search for "MCP Adapter".
- Click Install Now, then Activate.
Or install it with WP-CLI:
wp plugin install mcp-adapter --activateInstalled an earlier build from the GitHub releases page? Delete it first, then install from the directory so updates arrive through the normal dashboard.
Version 0.7.0 deprecated using the adapter as a bundled library. If a theme or plugin still ships its own copy, you will see a duplicate-copy notice. See Troubleshooting below.
How the default server works
Once the plugin is active, it registers a default MCP server at https://your-site.com/wp-json/mcp/mcp-adapter-default-server. That server offers three tools:
mcp-adapter/discover-abilitieslists the public abilities on the site.mcp-adapter/get-ability-inforeturns one ability's description and its input and output schemas.mcp-adapter/execute-abilityruns an ability with the arguments the AI built from that schema.
Your own abilities are not registered one by one in tools/list. A client that lists tools sees these three and nothing else, and that is by design. The AI calls discover, then get info, then execute.
Note the naming difference. In MCP tool calls the names use hyphens (mcp-adapter-discover-abilities), while ability names use a slash.
Want an ability to appear as its own direct tool? Create a custom server on the mcp_adapter_init hook with $adapter->create_server() and list the ability explicitly. Abilities without any public flag can only be reached this way.
Every request runs as a WordPress user. The default transport check is is_user_logged_in(), and each ability's own permission callback runs against that user. The user you connect with decides what the AI can do.
Option A: local site over STDIO
On a local site, the client can launch WP-CLI directly and talk to it over STDIO. No HTTP and no password are involved.
First, check the server from your terminal, inside the WordPress folder:
wp mcp-adapter list
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' | wp mcp-adapter serve --user=mcp-editor --server=mcp-adapter-default-server
echo '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"mcp-adapter-discover-abilities","arguments":{}}}' | wp mcp-adapter serve --user=mcp-editor --server=mcp-adapter-default-serverReplace mcp-editor with the login of a real user on the site. Here is what each command should return:
wp mcp-adapter listshows the registered servers.- The
tools/listcall returns the three tools above. - The discovery call returns the public abilities as JSON.
Next, add this to your client's MCP server configuration. Where the config lives depends on the client, so check its documentation.
{
"mcpServers": {
"wordpress-default": {
"command": "wp",
"args": [
"--path=/path/to/your/wordpress/site",
"mcp-adapter",
"serve",
"--server=mcp-adapter-default-server",
"--user=mcp-editor"
]
}
}
}Set --path to your WordPress root folder. The wp command must be on the PATH the client sees. If it isn't, use the full path to the WP-CLI binary.
Restart the client or reload its MCP servers. Then ask "Which WordPress abilities can you use?" It should call the discovery tool and list them.
Option B: live site over HTTP
For a site on a server, the client talks to @automattic/mcp-wordpress-remote. This is a small proxy that runs on your machine through npx, so Node.js must be installed. It turns the client's STDIO traffic into authenticated HTTP calls to the default server.
- Create a dedicated user in Users > Add New, for example
mcp-editor. Give it the lowest role that still passes the permission checks of the abilities you need. Author or Editor covers most content work. Never use Administrator. - Edit that user, scroll to Application Passwords, enter a name such as "Claude Code", and click Add New Application Password.
- Copy the generated password. WordPress shows it only once.
- Add the config below to your client with your HTTPS URL, the username and the Application Password.
{
"mcpServers": {
"wordpress-live": {
"command": "npx",
"args": ["-y", "@automattic/mcp-wordpress-remote@latest"],
"env": {
"WP_API_URL": "https://example.com/wp-json/mcp/mcp-adapter-default-server",
"LOG_FILE": "/path/to/mcp-wordpress-remote.log",
"WP_API_USERNAME": "mcp-editor",
"WP_API_PASSWORD": "xxxx xxxx xxxx xxxx xxxx xxxx"
}
}
}
}LOG_FILE is where the proxy writes its log, which helps when a connection fails. Keep this config out of Git, because it contains a live credential. To cut off access, revoke the Application Password on the user's profile.
Add your own read-only ability
Now give the AI something useful and safe to call. We'll register bmc/list-recent-posts, a read-only ability that returns the latest published items of any public post type. Custom post types created with JetEngine are ordinary post types, so a JetEngine CPT slug works too.
Don't copy the example in the adapter's GitHub README onto a live site. It lets the caller choose the post status, including draft or private, while only checking the read capability, which every Subscriber has. Any logged-in user could then pull drafts and private posts through MCP.
Our version hard-codes post_status to publish. The read check then matches the data, because the ability returns nothing that isn't already public.
Keep these rules in mind:
- Register on
wp_abilities_api_init, not oninit. - Use a namespaced name with a slash, like
bmc/list-recent-posts. - Setting
meta.publicto true exposes the ability, including on the default MCP server. meta.mcp.publicoverrides that for MCP only.falsehides a public ability from MCP, andtrueexposes an otherwise private ability to MCP only. We set both so you can see the shape.- On WordPress 6.9 and 7.0,
meta.publiccovers MCP but not the REST API, which still needsmeta.show_in_restset to true. From 7.1, core appliesmeta.publicto REST as well. - Return plain arrays that match
output_schema.
Create the file wp-content/mu-plugins/bmc-mcp-abilities.php and paste the code below. Create the mu-plugins folder first if it doesn't exist. Must-use plugins load automatically, so there is nothing to activate.
Code
<?php
/**
* Plugin Name: BMC MCP Abilities
* Description: Read-only MCP ability that lists recent published posts of a public post type.
* Version: 1.0.0
* Requires at least: 6.9
* Requires PHP: 7.4
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
add_action( 'wp_abilities_api_init', 'bmc_register_mcp_abilities' );
/**
* Register the bmc/list-recent-posts ability.
*/
function bmc_register_mcp_abilities() {
if ( ! function_exists( 'wp_register_ability' ) ) {
return;
}
wp_register_ability(
'bmc/list-recent-posts',
array(
'label' => __( 'List recent posts', 'bmc' ),
'description' => __( 'Returns the most recent published items of a public post type: ID, title, date and link. Never returns drafts, private posts or post content.', 'bmc' ),
'category' => 'site',
'input_schema' => array(
'type' => 'object',
'properties' => array(
'post_type' => array(
'type' => 'string',
'description' => 'Public post type slug, for example post, page or a JetEngine CPT slug.',
'default' => 'post',
),
'number' => array(
'type' => 'integer',
'description' => 'How many items to return.',
'minimum' => 1,
'maximum' => 20,
'default' => 5,
),
),
'additionalProperties' => false,
),
'output_schema' => array(
'type' => 'array',
'items' => array(
'type' => 'object',
'properties' => array(
'ID' => array( 'type' => 'integer' ),
'title' => array( 'type' => 'string' ),
'date' => array( 'type' => 'string' ),
'link' => array( 'type' => 'string' ),
),
'required' => array( 'ID', 'title', 'date', 'link' ),
),
),
'execute_callback' => 'bmc_list_recent_posts',
// Safe with 'read' only because the query below is hard-coded to published posts.
'permission_callback' => function () {
return current_user_can( 'read' );
},
'meta' => array(
'public' => true, // Exposed to clients, including the default MCP server.
'mcp' => array( 'public' => true ), // MCP-only override; false would hide it from MCP.
// On WordPress 6.9 and 7.0, REST API access also needs:
// 'show_in_rest' => true,
),
)
);
}
/**
* Execute callback: returns plain arrays that match output_schema.
*
* @param array $input Input sent by the client.
* @return array|WP_Error
*/
function bmc_list_recent_posts( $input = array() ) {
$input = is_array( $input ) ? $input : array();
$post_type = isset( $input['post_type'] ) ? sanitize_key( $input['post_type'] ) : 'post';
$number = isset( $input['number'] ) ? absint( $input['number'] ) : 5;
$number = max( 1, min( 20, $number ) );
if ( ! post_type_exists( $post_type ) || ! get_post_type_object( $post_type )->public ) {
return new WP_Error( 'bmc_invalid_post_type', __( 'Unknown or non-public post type.', 'bmc' ) );
}
$posts = get_posts(
array(
'post_type' => $post_type,
'post_status' => 'publish', // Never let the caller choose the status.
'has_password' => false, // Skip password-protected posts.
'posts_per_page' => $number,
'orderby' => 'date',
'order' => 'DESC',
'no_found_rows' => true,
)
);
$items = array();
foreach ( $posts as $post ) {
$items[] = array(
'ID' => (int) $post->ID,
'title' => wp_strip_all_tags( get_the_title( $post ) ),
'date' => (string) get_post_time( 'c', true, $post ),
'link' => esc_url_raw( (string) get_permalink( $post ) ),
);
}
return $items;
}How the ability works and how to test it
- Input:
post_typeis cleaned withsanitize_key().numberis clamped to 1-20 in PHP, even if a client ignores the schema. - Post type check:
post_type_exists()and thepublicflag fromget_post_type_object()stop the AI from reading non-public types such as navigation menu items. - Query:
get_posts()runs withpost_statusfixed topublish, andhas_passwordset to false skips password-protected posts. - Output: each item has only an ID, a title, an ISO 8601 date in GMT and a permalink. Post content and raw
WP_Postobjects never leave the site. - Permission: if you later add drafts, raise the check to match the data, for example
edit_others_postsfor other people's drafts.
Test it
- Run the discovery command from Option A again.
bmc/list-recent-postsshould now appear in the result. - In your MCP client, ask: "Use the WordPress tools to show the 5 most recent published items of type post." Replace
postwith any public post type slug that exists on your site, such as your JetEngine CPT slug. The AI calls discovery, reads the ability info, and builds theexecute-abilitycall itself. You should get back IDs, titles, dates and links. - Ask for a post type that doesn't exist, or a non-public one. You should get the "Unknown or non-public post type" error instead of data.
Troubleshooting
- My ability doesn't show in tools/list. Expected on the default server. The AI goes through discover, get info and execute. For a direct tool, list the ability in a custom server.
- ability_not_found when calling your own ability. Since 0.7.1, abilities that are not exposed through MCP return the same error as unknown names. Check these in order:
meta.publicis true.meta.mcp.publicis not false.- The permission callback passes for the connected user.
- The file sits directly in
mu-plugins, not in a subfolder. WordPress does not auto-load subfolders there.
- Admin notice about a duplicate MCP Adapter copy. A theme or plugin bundles its own copy. Keep the WordPress.org plugin and ask the author to drop the bundled one. Defining
WP_MCP_AUTOLOADas false hides the notice, but this is not recommended. - Connection errors right after updating. Version 0.7.1 caps stored session data at 4 KiB, and affected clients need to reconnect once. On multisite, the 0.6.0 update also required one reconnect. Restart the MCP server in your client.
- A tool, resource or prompt disappeared after 0.7.0. Malformed fields are no longer repaired, so the component is rejected. Check the debug log for a
_doing_it_wrongentry with the schema error path and fix the source. Then confirm withwp mcp-adapter list --protocol=2026-07-28. - Fatal error mentioning WP_CLI on normal page loads. This was a 0.6.0 bug, fixed in 0.6.1. Update the plugin.
- The ability works over MCP but not over the REST API. On WordPress 6.9 and 7.0, add
'show_in_rest' => truetometa. - Claude.ai web connector says "Your account was authorized, but no MCP server was found at the provided URL". This is reported in GitHub issue #361, opened 1 October 2026. It is still open with no maintainer reply. Use a config-file client instead, such as Claude Code, Claude Desktop, Cursor or VS Code, with the STDIO or proxy setup above.
Security checklist
- Exposure is opt-in. Only mark an ability public if its output is something the connected user may see anyway.
- Connect with a dedicated, least-privilege user and its own Application Password. Revoke the password when the project ends.
- Use HTTPS for remote connections. Outside local environments, WordPress only offers Application Passwords on HTTPS sites.
- Don't run
wp mcp-adapter serve --user=adminon a production server. STDIO acts as whatever user you pass, with no password check in between. - The plugin is pre-1.0 and experimental, and 0.7.0 shipped breaking changes. Read the release notes before each update.
If you want custom abilities for your JetEngine data, or an MCP setup built and locked down for you, post a request on BoostMyCroco.
Frequently Asked Questions
Does the WordPress MCP Adapter work with Claude.ai web custom connectors?
Is it safe to let Claude Code access my live WordPress site?
Do I need Node.js to use MCP Adapter?
Can the AI edit posts or JetEngine data once it is connected?
What happened to the Automattic wordpress-mcp plugin?
Sources
- WordPress MCP Adapter 0.7.0 launches on the WordPress Plugin Directory (make.wordpress.org)
- Releases · WordPress/mcp-adapter · GitHub (github.com)
- WordPress MCP Adapter 0.7 Review (2026): Setup, Security, Verdict (instawp.com)
