wordpress-mcp
Provides tools for reading, backing up, deploying, and managing Elementor page layouts, including page settings, custom CSS, CSS cache clearing, and remapping attachment IDs between environments.
Provides tools for managing a WordPress site via the WP REST API, including site info, users, posts/pages, media, and ACF fields.
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., "@wordpress-mcpCreate a new WordPress page titled 'About Us' and set it as a draft."
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.
WordPress MCP — Site & Elementor Automation for AI Clients
26 tools for managing WordPress sites — users, posts/pages, media, ACF, plugin settings, writable Elementor layouts, and any other REST route — over the WP REST API, for any MCP client.
What is this?
WordPress MCP is a Model Context Protocol server that exposes WordPress site management over the WP REST API. One server instance manages one WordPress site — pick which site by pointing --config at that site's config file, so a single MCP client can run several instances for several sites.
Beyond the standard content-management surface, it can read, back up, and write Elementor page layouts directly — something most WordPress tooling doesn't expose, because Elementor registers those fields for REST itself rather than through a public API. It can also reach any other REST route a plugin exposes, and change plugin settings safely through per-plugin adapters that handle the read-modify-write traps those routes tend to have.
Related MCP server: wp-mcp
Tools
Category | Tools | What you can do |
Site | 1 | Basic site info (name, URL, WP version) |
Users | 5 | List, get, create, update, delete |
Posts & Pages | 5 | List, get, create, update, delete — any post type by REST base slug |
ACF Fields | 2 | Read/write ACF field data where REST-exposed |
Media | 5 | List, get, find by filename, upload, delete |
Elementor | 4 | Read a layout, back it up, clear the CSS cache, and deploy a layout between environments with attachment IDs remapped |
Generic REST | 1 | Call any other REST route a plugin exposes |
Plugin Settings | 2 | Read/change a plugin's settings safely through a per-plugin adapter |
Diagnostics | 1 | How many requests this server has sent to the site so far |
Tool | Description |
| Basic site info (name, URL, WP version, description) |
| User management |
| Works with any post type by REST base slug ( |
| Read/write ACF field data, when a site has ACF fields exposed via REST |
| Media library management |
| Read a page's parsed layout, page settings (incl. |
| Save a page's current Elementor layout and settings to a timestamped local JSON file before any overwrite |
| Clear Elementor's generated CSS cache site-wide — required after writing |
| Deploy a layout to a page: back up what's there, upload media, remap attachment IDs/URLs for the target site, validate, then write |
| Generic authenticated call to any REST route on the site (a plugin's own namespace, or a core route the tools above don't cover). Route only; the |
| Read and safely change a plugin's settings through a per-plugin adapter (see Plugin settings adapters). |
| How many HTTP requests this server has sent to the site so far, login included, so the count AGENTS.md asks for after touching a live or staging site is a lookup |
Elementor pages
wp_create_post / wp_update_post accept a meta object, which is what makes Elementor layouts writable — Elementor registers these keys for REST itself (elementor/modules/wp-rest/classes/elementor-post-meta.php, hooked unconditionally on rest_api_init):
Key | Type | Notes |
| string | the whole layout, as a JSON string |
| string | set to |
| string | e.g. |
| object | accepts |
| array | Pro only |
Pair with template: "elementor_canvas" for a page with no theme header/footer. Elementor regenerates its per-post CSS file automatically after the write.
Two things worth knowing before pointing this at anything that matters:
There is no undo.
wp_backup_elementor_pagesaves the existing layout before you overwrite it — REST writes replace it wholesale and WordPress keeps no revision of post meta.sanitize_elementor_data()runs the payload throughkses_post_deepfor any user without theunfiltered_htmlcapability, silently stripping attributes. Confirm the target user has it before trusting a write.
Media IDs and URLs are embedded in the layout JSON, so a layout moved between environments needs its attachment IDs remapped — wp_deploy_elementor_page handles this by uploading media first (idempotent by filename) and rewriting the IDs before writing the page.
See ELEMENTOR_FINDINGS.md for the underlying research this was built from.
Plugin settings adapters
Plenty of plugins keep their settings behind their own REST routes, and those routes rarely behave like "PATCH these keys". Typical traps: a save replaces the stored object from what you send plus the plugin's defaults (so a partial POST silently resets everything else), read-only counters come back in the GET and must not be posted, text fields are sanitised in ways that change line breaks, and even a read can have a side effect. An adapter is where one plugin's route shape and its traps live, behind one interface:
wp_plugin_settings_get(plugin, group?, keys?)— nogrouplists the groups (no request sent).wp_plugin_settings_update(plugin, changes, dry_run=true, fix_line_breaks=false)—changesis{group: {setting: value}}. The adapter reads the full current object, rejects unknown keys and wrong-typed values, changes only what you asked, saves the whole object back, and verifies the result from the plugin's own save response. The dry run shows the exact plan and writes nothing. Both reportrequests_sent.
Adapters so far:
| Covers |
| Print Invoice & Delivery Notes for WooCommerce v7+: |
To add one, subclass SettingsAdapter in plugin_settings/, register it in
plugin_settings/__init__.py, and test it against a fake client — tests/test_wcdn_adapter.py shows the
pattern (the fake reproduces the plugin's quirks, so the tests fail if the adapter stops handling them).
plugin_settings/wcdn.py documents each quirk it handles and how it was found. For anything an adapter
doesn't cover yet, wp_rest_request reaches any route — read the object first and send it back whole.
Auth modes
Two, and which you need depends on how the site is protected.
Mode | Use when | Config keys |
| Normal site, no HTTP Basic auth in front of it |
|
| Site sits behind htpasswd, or you only have a normal login |
|
Application passwords cannot be used behind HTTP Basic auth. Both rely on the Authorization: Basic header and the basic-auth layer consumes it first. That is what cookie mode exists for — it logs in via the form and authenticates with a REST nonce, leaving Authorization free for htpasswd.
wp_login_url covers sites that move or hide wp-login.php (WPS Hide Login and similar); give it the slug or a full URL. Cookie logins also append a cache-buster automatically, because managed hosts will serve a cached login page with Set-Cookie stripped — see AGENTS.md for why that surfaces as a misleading "Incorrect username or password".
Safety rails (optional, per site)
Key | Default | Effect |
|
| Refuse every request that is not a |
|
| Minimum seconds between requests, login included. Set e.g. |
Requirements
Requirement | Version |
Python | 3.9 or later |
WordPress | Any version with the REST API enabled (default since WP 4.7) |
Installation
git clone https://github.com/jimsimoy/wordpress-mcp.git
cd wordpress-mcp
pip install -r requirements.txt
cp config.example.json configs/my-site.json
# edit configs/my-site.json with your site's URL and credentialsSite configs live in configs/*.json and are gitignored — they hold live credentials and should never be committed. See config.example.json for the full config schema.
Client Setup
python3 server.py --config configs/my-site.jsonThis starts an MCP server over stdio. Point an MCP client at it, e.g.:
{
"mcpServers": {
"wordpress-my-site": {
"command": "python3",
"args": ["/path/to/wordpress-mcp/server.py", "--config", "/path/to/configs/my-site.json"]
}
}
}Security
configs/*.jsonis gitignored — those files hold live credentials and should never be committed. Keep one config file per site.This repo is public, so the included git helpers scan before they act:
./git-pull-current.sh pull the current branch, then show status ./git-push-current.sh scan, then push the current branch ./git-commit.sh "message" scan the message, stage all, commit, pushThey check the outgoing diff and the commit message for credentials, private keys,
user:passpairs,.localhostnames, IPs, and email addresses, and refuse to push if anything matches — a force-push cannot unpublish a mistake, since old objects stay fetchable by SHA, so the only reliable moment to catch one is before it leaves. For names that must never appear here, add a pattern to.git-deny-patterns(gitignored, never ships).Using this against live or staging sites: if an AI agent is driving this tool, see AGENTS.md first — it sets the rate-limiting policy for any config pointed at a live or staging site (space out requests, no retry loops, no bulk calls) and requires reporting a hit-count summary at the end of a task.
Tests
python3 -m unittest discover -s tests -vNo network and no WordPress needed: the client guards (path validation, read_only, pacing, request
counting) and the adapters are tested against fakes.
Notes
ACF tools only work if the target field group(s) have
show_in_restenabled; otherwise the tools report that no ACF data is visible rather than guessing.
Project Structure
server.py # MCP server entry point and tool definitions
wp_client.py # WordPress REST API client
plugin_settings/ # Per-plugin settings adapters
configs/ # Per-site config files (gitignored)The server communicates over stdio using JSON-RPC 2.0, the standard MCP transport.
License
MIT — free to use, modify, and distribute.
This server cannot be deployed
Maintenance
Related MCP Connectors
Manage WordPress blogs and WooCommerce shops from Claude, ChatGPT, Cursor and other MCP apps.
WordPress MCP server: publish posts, AI images, SEO and full site management, self-hosted
WordPress MCP server: generate SEO posts, AI images, autoblog & WooCommerce on your self-hosted site
Security-first WordPress MCP server. 129 tools for Claude, ChatGPT, Gemini. Free on wp.org.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceAn MCP server that enables AI agents to manage WordPress sites, including Elementor page building, content CRUD, plugin management, and site configuration via the WordPress REST API.67 npmISC
- AlicenseNot gradedqualityCmaintenanceMCP server for WordPress content management via REST API, supporting posts, pages, media, comments, and terms through natural language interfaces like Cursor, ChatGPT, Codex, and Claude.16 npmMIT
- AlicenseNot gradedqualityCmaintenanceAn MCP server for managing multiple WordPress sites via the WordPress REST API. It supports posts, categories, tags, media, comments, and site configuration through natural language.67 npmISC
- AlicenseBqualityCmaintenanceEnables MCP-compatible clients to securely operate a WordPress site through a signed REST API, managing plugins, content, themes, menus, media, users, WooCommerce, Elementor, audits, and allowlisted WP-CLI commands.5855 npmMIT