Turn your WordPress site into an MCP server that AI tools like Claude and Cursor can interact with directly. Learn how to set it up using the Abilities API and MCP Adapter and I’ll share a handy abilities plugin you can use to get started.
If you’ve been using AI tools like Claude or Cursor for coding, you’ve probably wondered whether they could do more than just help you write code. What if they could actually interact with your WordPress site? Create posts, check settings, manage content, all through a conversation.
That’s what the Model Context Protocol (MCP) makes possible. And as of WordPress 6.9, your site already has the built-in infrastructure to support it.
What is MCP?
MCP stands for Model Context Protocol. It’s an open standard, created by Anthropic, that defines how AI tools communicate with external systems.
Think of it like a USB-C port for AI. Without MCP, every integration between an AI tool and an external system is a custom, one-off project. With MCP, the AI speaks one standard protocol and any system that implements it becomes accessible.
You’re probably already using MCP clients without thinking about it. Claude Desktop, Claude Code, Cursor, and VS Code with GitHub Copilot all support MCP. When you connect one of these to an MCP server, the AI can discover what tools are available and use them in conversation.
WordPress can now be one of those servers.
Benefits of an MCP Server on WordPress?
The biggest thing MCP gives you is the ability for AI to take real actions on your site. Not just answer generic WordPress questions, but actually create posts, read your content, and check settings on your specific site.
MCP also gives the AI structured discovery. Before doing anything, the AI can ask “what tools do you have?” and get back a list of available abilities with their input schemas. Compare that to handing an AI your REST API and hoping it figures out the right endpoints.
Security is handled at the WordPress level. Every ability has a permission_callback, and authentication uses WordPress application passwords. You control exactly what the AI can and can’t do. And because everything runs through WordPress’s normal post revision system, you get a full audit trail of every change.
What About the REST API and WP-CLI?
After setting this up and using it for a while, I’ve come to think of MCP and the REST API/WP-CLI as tools for different jobs.
- MCP Server
- Content changes (creating, editing, managing posts and pages)
- Working with the site like an admin user
- Structured discovery (the AI asks “what can I do?” before acting)
- REST API / WP-CLI
- Developer tasks
- Debugging and maintenance
- Database operations and deployment workflows
You don’t need to tell an LLM how to use the REST API. It already knows. You might even have a WordPress REST API skill configured that your LLM is already using for developer tasks. MCP fills a different niche: giving the AI a structured, permission-controlled way to do the things you’d normally do in wp-admin.
How WordPress AI Abilities Work
The WordPress MCP setup has two layers. The Abilities API (built into WordPress core since 6.9) is a registration system where plugins declare discrete actions they can perform. Each ability has an input schema, output schema, execution callback, and permission callback. It’s WordPress’s way of saying “here’s what I can do” in a machine-readable format.
The MCP Adapter (an official WordPress plugin) takes all registered abilities and exposes them over the MCP protocol. It’s the bridge that translates the Abilities API into something MCP clients understand.
Here’s a minimal example. This registers a single ability that returns basic site information:
<?php
add_action( 'wp_abilities_api_init', function () {
wp_register_ability(
'my-plugin/site-info',
array(
'category' => 'my-plugin',
'label' => 'Site Info',
'description' => 'Get basic site information.',
'permission_callback' => function () {
return current_user_can( 'read' );
},
'execute_callback' => function () {
return array(
'name' => get_bloginfo( 'name' ),
'url' => home_url(),
'version' => get_bloginfo( 'version' ),
);
},
'meta' => array(
'show_in_rest' => true,
'mcp' => array( 'public' => true ),
),
)
);
});The permission_callback controls who can call the ability (here, any authenticated user with the read capability). The execute_callback is the actual logic that runs when the ability is invoked. The show_in_rest flag exposes it through the REST API (required for the MCP Adapter to access it), and meta.mcp.public tells the MCP Adapter to advertise this ability to clients during discovery.
Abilities must be registered on the wp_abilities_api_init hook. Categories (used to group abilities for discovery) go on wp_abilities_api_categories_init.
Setting Up Your WordPress MCP Server
Installing the MCP Adapter Plugin
The Abilities API is already in WordPress core (6.9+). You just need to install the MCP Adapter plugin to expose those abilities over MCP.
Managed hosts: Some managed WordPress hosts like Pressable may offer the option to install the MCP Adapter automatically. Check your host’s dashboard or documentation first.
Self-hosted / manual install: You can download the latest release from the MCP Adapter GitHub releases page, or clone and install via Composer:
cd wp-content/plugins/
git clone https://github.com/WordPress/mcp-adapter.git
cd mcp-adapter && composer install
wp plugin activate mcp-adapterThe MCP Adapter supports two transport modes. STDIO runs the adapter as a WP-CLI command and is best for local dev environments. HTTP exposes a REST endpoint that MCP clients connect to through the @automattic/mcp-wordpress-remote package as a proxy. You’ll use HTTP for managed hosting or any site you access remotely.
Application passwords are required for the HTTP transport. We’ll set that up next.
Creating a Dedicated MCP User
Don’t use your admin account for MCP. Create a dedicated user instead. This gives you scoped capabilities (only grant what the AI needs), a clear audit trail in post revisions, and easy revocation if you ever need to cut off access.
Create the user in wp-admin (Users → Add New). But which role should you assign?
Here’s the thing: when a WordPress user lacks the unfiltered_html capability, WordPress applies wp_kses_post to all content they save. This is normally fine, but it will corrupt code blocks containing HTML, PHP, or JSX (tags get stripped), block comment attributes containing code (JSON gets mangled), and any markup that looks like HTML but isn’t meant to be rendered.
The Contributor and Author roles don’t have unfiltered_html. Editor and Administrator do, but those roles grant *far* more capabilities than an MCP agent needs.
The better approach is a must-use plugin that creates a custom role with exactly the capabilities you need. Drop this file in wp-content/mu-plugins/mcp-agent-role.php:
<?php
/**
* Plugin Name: MCP Agent Role
* Description: Creates a custom role for MCP AI agents with content management caps + unfiltered_html.
*/
add_action( 'init', function () {
$version = 1;
if ( (int) get_option( 'mcp_agent_role_version' ) === $version ) {
return;
}
remove_role( 'mcp_agent' );
add_role(
'mcp_agent',
'MCP Agent',
array(
// Read.
'read' => true,
// Posts.
'edit_posts' => true,
'edit_others_posts' => true,
'edit_published_posts' => true,
'publish_posts' => true,
'delete_posts' => true,
'delete_others_posts' => true,
'delete_published_posts' => true,
// Pages.
'edit_pages' => true,
'edit_others_pages' => true,
'edit_published_pages' => true,
'publish_pages' => true,
'delete_pages' => true,
'delete_others_pages' => true,
'delete_published_pages' => true,
// Media.
'upload_files' => true,
// Critical for code blocks.
'unfiltered_html' => true,
)
);
update_option( 'mcp_agent_role_version', $version );
});After adding the mu-plugin, create a new user with the MCP Agent role and generate an Application Password for that user (Users → Edit User → Application Passwords).
A few security notes on this approach. The unfiltered_html capability allows saving arbitrary HTML. That’s acceptable when the user is a controlled AI agent authenticated via application password, but you should understand the tradeoff. On WordPress multisite, unfiltered_html is restricted to Super Admins by default and can’t be granted to custom roles through add_role alone.
This role intentionally excludes manage_options, activate_plugins, and other administrative capabilities. Add them only if you need them. And if you update the cap list later, just bump the $version number and the role will be recreated on the next page load.
Don’t Sanitize Content in Ability Callbacks
When writing ability callbacks that create or update posts, you might be tempted to run the content through wp_kses_post before passing it to wp_insert_post. Don’t.
WordPress core already handles content sanitization internally. When wp_insert_post processes post_content, it checks whether the current user has unfiltered_html. If they don’t, it applies wp_filter_post_kses automatically. If they do, the content passes through untouched.
If you apply wp_kses_post in your callback, the content gets sanitized regardless of the user’s capabilities. Your MCP user might have unfiltered_html, but the callback strips the HTML before WordPress even gets a chance to check. I learned this the hard way when my Code Block Pro blocks were getting silently corrupted on save.
The rule: let WordPress core handle content sanitization. Sanitize other fields (titles, slugs, status) normally, but leave post_content and post_excerpt to core.
Registering Abilities
Now for the fun part: registering the abilities that define what your AI can do.
I’ve published a companion plugin, MCP Abilities, that you can install directly or use as a starting point. It registers six content management abilities: site info, list posts, get post, create post, update post, and delete post.
When I first set this up, I was expecting there to be a set of core abilities or something that could cover things like updating posts and whatnot. However, there are only a few core abilities installed and they’re very simple, like getting the site title and things like that.
This means that any abilities you want to use must be created by something (like a plugin, mu-plugin, etc). If you just install the adapter and ask it to do things, it will show only an empty list of abilities.
Category registration: Categories group abilities for discovery. MCP clients see them as organizational labels.
<?php
add_action( 'wp_abilities_api_categories_init', function () {
wp_register_ability_category(
'mcp-abilities',
array(
'label' => 'Content Management',
'description' => 'Abilities for managing site content via MCP.',
)
);
});A read ability, list-posts: This is a more complex example with an input_schema that defines optional parameters for filtering and pagination:
<?php
wp_register_ability(
'mcp-abilities/list-posts',
array(
'category' => 'mcp-abilities',
'label' => 'List Posts',
'description' => 'List posts with optional filtering by status, type, and search term.',
'input_schema' => array(
'type' => 'object',
'properties' => array(
'post_type' => array(
'type' => 'string',
'default' => 'post',
'description' => 'Post type slug.',
),
'post_status' => array(
'type' => 'string',
'default' => 'publish',
'description' => 'Post status.',
),
'search' => array(
'type' => 'string',
'default' => '',
'description' => 'Search term.',
),
'per_page' => array(
'type' => 'integer',
'default' => 20,
'description' => 'Number of results per page.',
),
),
),
'output_schema' => array(
'type' => 'object',
'properties' => array(
'posts' => array( 'type' => 'array' ),
'total' => array( 'type' => 'integer' ),
'total_pages' => array( 'type' => 'integer' ),
),
),
'permission_callback' => function () {
return current_user_can( 'read' );
},
'execute_callback' => 'mcp_abilities_list_posts',
'meta' => array(
'show_in_rest' => true,
'mcp' => array( 'public' => true ),
),
)
);The input_schema uses JSON Schema format to describe what parameters the ability accepts. MCP clients use this to understand what arguments they can pass. Default values mean the AI doesn’t need to specify every parameter.
A write ability, create-post: This is the ability that tends to trip people up. Pay attention to the content handling:
<?php
wp_register_ability(
'mcp-abilities/create-post',
array(
'category' => 'mcp-abilities',
'label' => 'Create Post',
'description' => 'Create a new post or page.',
'input_schema' => array(
'type' => 'object',
'properties' => array(
'title' => array(
'type' => 'string',
'description' => 'Post title.',
),
'content' => array(
'type' => 'string',
'description' => 'Post content (HTML or block markup).',
),
'author' => array(
'type' => 'integer',
'description' => 'User ID to assign as post author.',
),
),
'required' => array( 'title' ),
),
'permission_callback' => function () {
return current_user_can( 'edit_posts' );
},
'execute_callback' => function ( $input ) {
$post_args = array(
'post_title' => sanitize_text_field( $input['title'] ),
'post_status' => 'draft',
);
if ( isset( $input['content'] ) ) {
// Let wp_insert_post handle sanitization.
// It respects the unfiltered_html capability.
$post_args['post_content'] = $input['content'];
}
if ( isset( $input['author'] ) ) {
$post_args['post_author'] = absint( $input['author'] );
}
$post_id = wp_insert_post( $post_args, true );
if ( is_wp_error( $post_id ) ) {
return array( 'error' => $post_id->get_error_message() );
}
return array( 'id' => $post_id );
},
'meta' => array(
'show_in_rest' => true,
'mcp' => array( 'public' => true ),
),
)
);Notice the author field. The MCP user is authenticated and makes the API call, but you can set your own user ID as the post author so it shows your byline. I actually use this when I’m publishing things to this site myself. 1
The companion plugin also includes abilities for updating and deleting posts. You can extend it with abilities for plugin management, options, media, or anything else. The README includes an example for listing plugins.
Connecting an MCP Client
With the MCP Adapter installed and abilities registered, let’s connect an AI tool to your site.
If you’re working locally with WP-CLI, use the STDIO (standard input/output) transport:
{
"mcpServers": {
"wordpress": {
"command": "wp",
"args": ["mcp-adapter", "serve"],
"cwd": "/path/to/wordpress",
"env": {
"WP_CLI_USER": "mcp-agent"
}
}
}
}For a remote or hosted site, use the HTTP transport:
{
"mcpServers": {
"wordpress": {
"command": "npx",
"args": ["-y", "@automattic/mcp-wordpress-remote@latest"],
"env": {
"WP_API_URL": "https://example.com/wp-json/mcp/mcp-adapter-default-server",
"WP_API_USERNAME": "mcp-agent",
"WP_API_PASSWORD": "xxxx xxxx xxxx xxxx xxxx xxxx"
}
}
}
}You’ll need to generate an Application Password for the new MCP user you created earlier. To do this, go to edit that user and scroll towards the bottom of the user profile fields.
You’ll see a place to generate a new Application password. Once you give it a name, the password generates and displays just once, so make sure you copy it before you close the page or navigate away.
The WP_API_PASSWORD is the application password you generated for the MCP user. Note the spaces, WordPress application passwords are formatted with spaces between groups.
If you’re using nvm (or another Node version manager) locally, you may need to use the full path to npx in the command field instead of just "npx". MCP clients don’t always inherit your shell’s PATH, so npx by itself may not resolve. You can find the full path with which npx in your terminal.
Where to put this config depends on your client. For Claude Desktop, it goes in ~/Library/Application Support/Claude/claude_desktop_config.json on macOS. For Claude Code, use .mcp.json in your project root (or globally in ~/.claude/). For Cursor, go to Settings → MCP Servers.
After adding the config, restart the client. The AI should discover your abilities and you’ll be able to use them in conversation.
Using AI to Manage Your Content
Once connected, the workflow is conversational. You ask the AI to check what’s on the site and it calls site-info and list-posts. You ask it to create a new post and it calls create-post with a title, content, your user ID as the author, and a status of draft. Then it calls get-post to verify the content was created correctly and hands you the edit link.
This is how I published the post you’re reading right now. The AI created the draft, I reviewed it in the editor, and published.
While you can tell Claude (and other models, I’m sure) to use Chrome and view the page, it may not always understand what “correct” looks like or otherwise tell you it’s right when it clearly as is not. As always, you should double check anything you have an LLM building for you.
If nothing else, you want posts to sound like they were written by a person. Using AI to scaffold things, draft posts, write outlines, that stuff speeds up the regular human creative process, but doesn’t replace it.
Using AI to save time allows you to take a bit more time to make sure things are correct, so don’t skip it.
WordPress 7.0 and AI Connectors
Everything in this post covers what I’d call inbound AI: external AI tools reaching into WordPress through MCP to read and modify content. WordPress 7.0 adds the ability to use outbound AI, where WordPress plugins reach out to AI services.
There are two new APIs coming to enable these features:
The AI Connectors API is a centralized system for managing connections to AI providers. Instead of every plugin storing its own API keys, WordPress adds a Settings → Connectors screen where administrators configure provider credentials once. Three providers are supported at launch: OpenAI, Google (Gemini), and Anthropic (Claude).
The AI Client API is a provider-agnostic PHP interface that lets plugins send prompts to any configured AI model via wp_ai_client_prompt(). Plugins describe what they need, and WordPress routes the request to whichever provider the admin has configured. Think of a plugin that auto-generates alt text for images, or suggests post excerpts.
Together with the Abilities API and MCP Adapter, this creates a full bidirectional AI architecture. Inbound: AI agents connect through the MCP Adapter to call abilities in WordPress (what we covered in this post). Outbound: WordPress plugins call out to AI services through the AI Client and Connectors APIs (coming in 7.0).
As of this writing, WordPress 7.0 is not out but it should be in April 2026. The Connectors and AI Client APIs may change before the final release, but the direction is clear: WordPress is building first-class infrastructure for AI in both directions.
Further Reading
- WordPress Abilities API (Developer.WordPress.org)
- MCP Adapter Plugin (GitHub)
- Introducing the WordPress Abilities API (WordPress Developer Blog)
- From Abilities to AI Agents: Introducing the WordPress MCP Adapter (WordPress Developer Blog)
- Model Context Protocol Specification (modelcontextprotocol.io)
- MCP Abilities Companion Plugin (GitHub)
- Introducing the Connectors API in WordPress 7.0 (Make WordPress)
- Introducing the AI Client in WordPress 7.0 (Make WordPress)
Happy coding!
- I started experimenting with this as a quicker way to get drafts up on the site. It’s definitely handy and saves time, but you still need to check things out and verify it looks like it should. ↩︎