Guarded MCP for WordPress
Provides tools for managing WordPress content through the Abilities API: reading, creating, and updating pages and posts (always as drafts, never publishing or deleting), managing taxonomy terms, uploading and updating media attachments via single-use links, and reading or modifying classic theme menus with dry-run validation and automatic backups. Includes a site-health diagnostics tool for versions, integrations, PHP lint, and the allowed blocks, taxonomies, and menu locations.
Reads and updates Yoast SEO title and description fields when fetching or changing pages and posts, so agents can manage on-page SEO metadata alongside content.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Guarded MCP for WordPressCreate a draft page titled "Refund Policy" with our standard intro blocks"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Guarded MCP for WordPress
A security-first MCP server for WordPress, built on the Abilities API and the MCP Adapter plugin. It gives AI agents 15 tools for pages, posts, terms, media and menus, and keeps a human in charge: content is saved as drafts, nothing can be deleted, raw HTML is rejected, uploads use single-use links, and menu changes are dry runs with automatic backups. The security model is documented as eight invariants in ARCHITECTURE.md.
Status: 0.1.0. The plugin was extracted from a module that runs on a live bilingual (English and Greek) site of my own project, where AI agents prepare pages and articles. Parts that only made sense for that site's theme stayed behind; what was hard-wired there (the theme's block namespace, menu locations, taxonomies) is configurable here. Why and how it was built: docs/case-study.md.
What an agent can do
Tool | What it does |
| Read a page by |
| Create a page as a draft from block markup checked against the allowlist. |
| Change the title, content or SEO fields of a page. WordPress keeps a revision. |
| Read a post: title, content, status, excerpt, categories, featured image, language, SEO fields. |
| Create a post as a draft, with existing categories and featured image only. |
| Change a post. The status never changes. |
| List terms of an allowed taxonomy, with language and translations under Polylang. |
| Create a term. Duplicate names and slugs are rejected. |
| Change a term's name, slug, description, parent, language or translation link. |
| Step 1 of an image upload: check alt, caption, title and language, return a single-use link and a ready |
| Read an image: URL of the |
| Change an image's alt, caption, title or language. The file is never touched. |
| Read the menus of every theme location (and language): the item tree, how the theme renders the location, the backups. |
| Add, change, move or remove menu items, replace a menu with a tree, or restore a backup. A dry run unless |
| Diagnostics: PHP lint of the plugin and theme, versions, active integrations, the blocks, taxonomies and menu locations the guard allows. |
There is no tool to publish or delete anything. The only removal is a menu item, and it removes the link, not the page.
Related MCP server: MCP Site Manager
Security model
The agent is treated as a partly trusted client: it acts for the site owner, but the model can be wrong, and text it reads can contain instructions the owner never gave. So the limits hold no matter what the agent sends:
Every tool checks a specific capability, and writes re-check it on the target object.
Content must consist of allowed blocks: your own block namespaces plus a narrow list of core blocks. Raw HTML outside blocks,
core/htmlandcore/shortcodeare rejected.HTML inside allowed blocks is filtered with the same rules WordPress applies to editors without
unfiltered_html. Full-content KSES is bypassed in one function only, after both checks, so block markup is stored intact.Pages and posts are always created as drafts. The bot role cannot publish or delete.
The token is compared with
hash_equals(); requests run as a low-privilege bot user, and a bot user with administrator-level rights is refused.The diagnostics tool takes no input, so it never reads a path from the client.
Images arrive through single-use links stored as hashes. The file type is read from the content, SVG is never accepted, and size and pixel limits stop "image bombs".
Menu changes are dry runs by default, every save is backed up first, and a failed save rolls back.
The threat model, the full rules and the 11 rejected design options are in ARCHITECTURE.md.
Requirements
WordPress 6.9 or later (tested on 7.1.3).
PHP 7.4 or later.
The MCP Adapter plugin, 0.7 or later (tested with 0.7.1). WordPress will not activate Guarded MCP without it.
Optional: Polylang for languages and translations, Yoast SEO for SEO title and description.
For menu tools: a theme with classic menu locations. Block themes manage navigation in the Site Editor, and the menu tools then report that no location is available.
Installation
Install and activate the MCP Adapter plugin, then this plugin.
Create the bot user. The role is created by the plugin; the user is created by you:
wp user create mcp-bot mcp-bot@example.com --role=guarded_mcp_bot wp user list-caps mcp-bot | grep -E 'unfiltered_html|publish_|delete_' # expect no outputTo use another login, define
GUARDED_MCP_BOT_LOGINinwp-config.php.Allow your own blocks. Out of the box only the trusted core blocks pass the guard. Add the namespace of your theme or block plugin:
add_filter( 'guarded_mcp_block_namespaces', function ( $namespaces ) { $namespaces[] = 'acme'; // acme/hero, acme/pricing, … return $namespaces; } );Read the token (it is generated on the first load):
wp option get guarded_mcp_tokenAdd the server to your MCP client. Leave the OAuth fields empty: the token in the URL is the authentication.
https://example.com/wp-json/guarded-mcp/v1/mcp?token=<token>Ask the agent to run
guarded-mcp-site-health. Expectall_ok: true,mcp_adapter_active: trueand 15 abilities.
Before you put the site on a public host, make sure the web server does not execute PHP in wp-content/uploads. That is a server setting, and it protects every upload, not only these.
Configuration
All settings are filters; there is no settings screen.
Filter | Default | Use it to |
| none | allow your theme's or plugin's blocks |
| 22 core blocks | add or remove trusted core blocks |
|
| allow extra HTML inside blocks, such as inline SVG |
|
| let the agent manage a custom taxonomy |
| every classic location, 2 levels | hide a location, set its real depth, describe how it renders |
|
| accept images smaller than the |
Details and the remaining filters: ARCHITECTURE.md.
How image upload works
The arguments of a tool call are written by the model token by token, so image bytes cannot travel inside one: a 1 MB PNG is 1.3 million characters of base64. Upload takes two steps instead:
prepare-media-uploadchecks alt, caption, title and language and returns a single-use link (valid 15 minutes, at most 10 open) with acurlcommand.The agent runs the command with the local file path. The response is the new attachment:
id,url_large,size_slug.
The link is used up by the first attempt, whatever the outcome. PNG, JPEG and WebP are accepted up to 10 MB (or the server limit), 8000 px per side and 25 megapixels. By default the image must be large enough for WordPress to make the large size, because block markup references it. Uploading the same file again in the same language returns the existing attachment. On Windows PowerShell the agent must call curl.exe, because plain curl there is an alias of Invoke-WebRequest.
Menus
A menu has no drafts or revisions: a saved change is live on every page at once. So update-menu validates the whole change on a model of the menu and returns the resulting tree without saving, unless the call passes dry_run: false. Every save first copies the menu into a backup (the last 10 per location and language), and restore_backup puts any of them back. With Polylang each language has its own menu, addressed by location and language. Creating menus and assigning them to locations stays with a person in Appearance → Menus.
Limitations
Classic menus only; no support for the Navigation block of block themes.
No custom fields on menu items (for example a theme's mega-menu fields).
Languages through Polylang only; WPML is not supported. SEO fields through Yoast SEO only.
The token is a long random string stored in the options table. Anyone who reads the database or the client configuration can use it. Rotate it with
wp option delete guarded_mcp_token.No rate limiting on the endpoints; use the web server or a firewall.
Not tested on multisite.
After a menu change on a site behind a CDN, the cache has to be purged: the header and footer are on every page.
How AI is involved in development
I develop this plugin with AI coding agents (Claude Code), and most of the code was written by an agent against a design I set. The trust boundary, the eight invariants, the rejected options and every check before a write are my decisions, written down in ARCHITECTURE.md before or alongside the code. Each change is reviewed against the checklist at the end of that file. The tests in tests/ were written with the agent and checked by breaking each guarded rule on purpose until a test failed; tests for five of the invariants (permission checks, raw HTML refusal, drafts only, upload file checks, single-use upload links) are being written by hand, without the agent.
Development
Requirements: Docker, Node.js 20, Composer.
composer install
npm install
npm run env:start # WordPress at http://localhost:8888 (admin / password)
npm run test:php # PHPUnit inside wp-env
npx playwright install chromium
npm run test:e2e # Playwright: markup saved over MCP opens in the block editor without validation errors
composer lint # PHPCS: WordPress and WordPress VIP coding standards
composer analyse # PHPStan, level 5The development site runs the latest WordPress with MCP Adapter and the Twenty Twenty-One theme, which has classic menu locations. The PHPUnit site runs as production (.wp-env.json), so the refusals that apply only in production are tested too. CI runs all of the above and a PHP 7.4–8.4 syntax check on every push and pull request.
License
GPL-2.0-or-later, the same as WordPress and the MCP Adapter. See LICENSE.
This server cannot be deployed
Maintenance
Related MCP Connectors
Manage a WordPress site from your AI assistant: read, search, propose edits, Search Console data.
Manage WordPress blogs and WooCommerce shops from Claude, ChatGPT, Cursor and other MCP apps.
Publish to self-hosted WordPress from AI agents: markdown, images, SEO, and Notion sync.
Security-first WordPress MCP server. 129 tools for Claude, ChatGPT, Gemini. Free on wp.org.
Related MCP Servers
- AlicenseCqualityCmaintenanceEnables AI agents to manage WordPress sites with 190+ tools for content management, theme/plugin customization, file system operations, WooCommerce, and complete site control through natural language.10038 npm56MIT
- FlicenseNot gradedqualityDmaintenanceEnables AI agents to manage WordPress sites via ~74 capabilities including content, media, plugins, themes, and more.-
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to manage WordPress sites through the WordPress REST API, supporting content, media, users, settings, and Elementor management with safety policies for production use.MIT
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to interact with WordPress websites through structured tools, supporting posts, pages, media, users, categories, tags, plugins, themes, menus, and WooCommerce with secure authentication.16 npmMIT