Documentation
Everything WP MCP does, and exactly how the safety net works.
WP MCP is the open-source plugin wpmcp, built on the official WordPress Abilities API. This section is for developers, agencies, and anyone connecting an AI client over MCP.
Introduction
wpmcp is a WordPress plugin that turns a site into an MCP (Model Context Protocol) server. It lets an AI agent, Claude, Cursor, or any other MCP-compatible client, read and edit a WordPress site directly: create and update posts and pages, manage media, adjust settings, and more.
The core promise
Handing an AI agent write access to a live WordPress site is risky. A bad edit on a client’s production site is the kind of mistake that is hard to walk back, and every other WordPress AI tool asks you to trust the model to get it right.
wpmcp takes the opposite approach: it assumes the agent will get something wrong eventually, and makes sure that nothing it does is permanent.
Nothing an agent does through wpmcp is unrecoverable. Every write goes through a safety engine that snapshots the affected object before the change happens. If the change breaks something, it can be rolled back, either by the agent itself (via a rollback tool) or by a human, with one click, from the WordPress admin screen. You can undo a single operation, or unwind an entire agent session back to where it started.
How this is different
Most AI-for-WordPress tools focus entirely on the building and editing experience. wpmcp treats recoverability as the headline feature, not an afterthought:
- Enforced in code, not by convention. No tool that mutates the database can bypass the safety wrapper. This is a structural guarantee, not a guideline the code happens to follow.
- Works at the WordPress data layer. Snapshots capture the actual post row, meta, terms, and comments, so rollback does not depend on understanding any particular page builder’s internal format.
- Runs inside WordPress. wpmcp is a single WordPress plugin built on the official WordPress Abilities API, not a separate Node process or local proxy. One install, and it works with any MCP client.
- Free and open where it matters. The safety engine and the core content/media/settings tools are free and GPL-2.0 licensed.
Who this is for
- Developers and agencies who want to let an AI agent build or maintain WordPress sites (including client sites) without babysitting every change.
- MCP client builders and power users connecting Claude Code, Claude Desktop, Cursor, or another MCP client to a WordPress install.
- Anyone nervous about giving an AI agent write access to production, and wants an undo button that actually works.
Project status
wpmcp is actively developed and past its feature-parity milestone: the safety engine (snapshot, apply, verify, rollback) and 407 registered abilities (274 free, 133 Pro) are shipped and covered by the test suite. A few integration paths (Polylang, WPML, multisite network calls, Google analytics/Search Console through Site Kit) are verified in production rather than CI, and release notes flag those honestly per release. Where this documentation describes a planned feature, it says so explicitly.
What it covers today
- Page builders. Gutenberg (free) and, on Pro, Elementor deep editing plus structural read and write for Bricks, Divi, WPBakery, Beaver Builder, Breakdance, Oxygen 6, classic Oxygen (4.x and earlier), Avada and Thrive Architect through
detect-builder,get-builder-contentandupdate-builder-content. Every builder write is an ordinary post snapshot, so it rolls back exactly. Classic Oxygen writes need Oxygen active, and pre-4.0 Oxygen pages are read-only. - Block suites and themes. On Pro, dedicated support for Kadence Blocks, GenerateBlocks, Spectra, Otter Blocks and the Blocksy companion blocks, with schema-checked writes and pattern import (including the WordPress.org Pattern Directory, on request only). Theme settings packs for Astra and the Kadence theme (free) and GeneratePress and Blocksy (Pro).
- WooCommerce. Products, variations, coupons, tax rates, orders, notes, sales reports and a two-step product import on the free tier; on Pro, a deep operations catalog for order create and edit, shipping zones and methods, webhooks, payment gateways with every secret masked, review moderation, totals reports, the system status report and brands. See WooCommerce Tools.
- Plugin integrations. SEO metadata for Yoast SEO, Rank Math, SEOPress, The SEO Framework, SureRank and Slim SEO (free) and All in One SEO (Pro); Redirection; ACF (values and structure), Meta Box, JetEngine and Pods; Polylang, WPML and TranslatePress; BuddyPress; forms (Contact Form 7 with Flamingo, Forminator, SureForms and MetForm free, and the Pro forms pack for Gravity Forms, WPForms, Formidable, Ninja Forms and Fluent Forms); events, donations and memberships (read); FunnelKit funnels (Pro: reads, plus undoable changes to funnels, steps and checkout products through FunnelKit itself); and read-only status for UpdraftPlus, Duplicator, Solid Security, MonsterInsights and W3 Total Cache, plus a W3 Total Cache purge. The full list, with limits, is on the integrations page.
Where to go next
- Getting started: requirements and installation.
- Connecting clients: wiring up Claude Code, Cursor, or Claude Desktop.
- The safety model: how snapshot, rollback, and recovery actually work under the hood.
- Tools reference: every MCP tool wpmcp ships, what it does, and whether it is safety-wrapped.
Getting Started
Requirements
| Dependency | Version |
|---|---|
| WordPress | >= 6.9 (this version bundles the Abilities API that wpmcp registers its tools on) |
| PHP | >= 8.1 |
| Composer | needed to install from source |
| MySQL / MariaDB | whatever your WordPress install already uses |
wpmcp is distributed from GitHub releases, not from the WordPress.org plugin directory.
Install the release zip
Download wpmcp.zip from the latest release (or use the direct link https://github.com/wpmcp/wpmcp/releases/latest/download/wpmcp.zip), then upload it in wp-admin under Plugins > Add New > Upload Plugin. With WP-CLI:
wp plugin install https://github.com/wpmcp/wpmcp/releases/latest/download/wpmcp.zip --activate
Install from source
If you would rather run from a checkout, clone the plugin directly into your wp-content/plugins directory and install its dependencies:
git clone https://github.com/wpmcp/wpmcp.git wp-content/plugins/wpmcp
cd wp-content/plugins/wpmcp
composer install --no-dev
--no-dev skips the PHPUnit/test tooling, which you do not need on a production or staging install. If you plan to contribute to the plugin itself, see Contributing and tests for the full dev setup instead.
Activate the plugin
- Log into wp-admin.
- Go to Plugins.
- Find wpmcp and click Activate.
On activation, wpmcp creates its snapshot storage table (wp_wpmcp_snapshots) and registers a wpmcp top-level admin menu item. That screen lists recent agent operations and lets a human restore any of them with one click, the same rollback mechanism the MCP tools use, just exposed to a person instead of an agent.
What activation does not do
Activating the plugin does not, by itself, expose write access to the outside world. An MCP client still needs valid WordPress credentials (an OAuth 2.1 grant approved by a signed-in user, or an Application Password) to call any tool, and every ability is capability-checked against edit_posts before it runs. See Connecting clients for how to actually wire up an AI agent.
Next steps
- Connecting clients: sign a client in over OAuth 2.1, or generate an Application Password, and point it at your site.
- The safety model: understand what happens before and after every write.
Connecting an MCP Client
wpmcp exposes its tools over the Model Context Protocol via the official WordPress Abilities API. Every ability wpmcp registers requires a caller to be authenticated as a WordPress user who can edit_posts, so the first step is deciding how the client signs in. There are two ways, and the WP MCP > Connection screen in wp-admin shows a ready-made config block for each client either way.
Option A: OAuth 2.1 (recommended for desktop and hosted clients)
wpmcp ships a full OAuth 2.1 authorization server with PKCE (S256 is mandatory), so an MCP client that supports OAuth signs in the way it signs in anywhere else: it opens your site, you log in as a WordPress user, approve the client, and the client receives a token. No password is ever pasted into a config file, and a connection can be lowered or revoked later without touching the client.
OAuth is off by default. Switch it on by defining WPMCP_OAUTH_ENABLED in wp-config.php (or returning true from the wpmcp_oauth_enabled filter):
define( 'WPMCP_OAUTH_ENABLED', true );
Then, in your client, add the MCP endpoint and let it discover the authorization server. The Connection screen lists the discovery addresses clients use for this site, including sites installed in a subdirectory.
When you approve a client you choose what it may do:
- Full access: the token can do what your user can do (the
mcpscope). - Read-only: the token may list and read, and is refused anything that changes the site (the
mcp:readscope). A client that asks only formcp:readis narrowed to it automatically. - A scoped identity (site owners): the connection is bound to one of your scoped identities, so governance decides what it may do.
A token never gains scope when it is refreshed, and lowering a connection’s access on the Connection screen takes effect on its next request without reconnecting. Clients can register dynamically or sign in with a client metadata document (an https URL as their client ID); site owners can require approval of new clients, and approve or block them, on the same screen. Blocking a client revokes its tokens.
Option B: an Application Password
For clients or scripts without OAuth support, wpmcp also accepts WordPress’s built-in Application Passwords. No separate API key system, no additional plugin.
Step 1: create an Application Password
- In wp-admin, go to Users -> Profile (or edit the specific user the agent should act as).
- Scroll to Application Passwords.
- Give it a name (e.g.
claude-code) and click Add New Application Password. - Copy the generated password immediately. It is shown once.
Use a dedicated user for agent access rather than your own admin account, so you can revoke it independently and see its actions clearly in the operations list.
Step 2: encode the credential
MCP clients that speak HTTP typically expect a Basic auth header, which is the base64 encoding of username:application-password:
echo -n "your-username:xxxx xxxx xxxx xxxx xxxx xxxx" | base64
Keep the spaces in the application password exactly as WordPress generated them before encoding.
Step 3: point your client at the MCP endpoint
Claude Code
Add an entry to your project’s .mcp.json:
{
"mcpServers": {
"wpmcp": {
"type": "http",
"url": "https://your-site.com/wp-json/mcp/wpmcp-server",
"headers": {
"Authorization": "Basic BASE64_OF_username:application-password"
}
}
}
}
Replace your-site.com with your actual domain and the Authorization value with the base64 string from step 2.
Cursor and Claude Desktop
Both are MCP-compatible clients, and the same endpoint and Basic-auth header work in their respective MCP server configuration. The .mcp.json example above will need to be adapted to whatever configuration format the client expects, but the URL and header are identical: no wpmcp-specific setup beyond the Application Password.
Local development: the WP-CLI stdio bridge
On a machine that has WP-CLI and the site’s files, a client can also run wpmcp over stdio through the bundled WP-CLI command, wp mcp-stdio serve, with no HTTP credentials at all; the client runs it as a local process and talks to it over stdin and stdout.
Verifying the connection
Once connected, ask your client to call the list-post-types or list-posts tool. If you get a result back, the connection and auth are working. If you get a 401/403, check that the WordPress user has at least the edit_posts capability (an Editor or Administrator role satisfies this by default); for an Application Password, double-check the base64 encoding too; for OAuth, check that WPMCP_OAUTH_ENABLED is defined and that the client was approved with the access level you expected.
See Tools reference for the full list of available tools once you are connected.
The Safety Model
This is the part of wpmcp that the rest of the product exists to support. Every tool that mutates existing data routes through a single orchestrator, Safe_Mutation::run(). No exceptions, and this is enforced in code: a tool cannot write to a post or option except by calling this method.
The snapshot -> apply -> verify -> rollback flow
snapshot (before) -> apply the change -> verify -> ok?
| | |
stored in on failure: return
wp_wpmcp_snapshots auto-rollback operation id
(keyed by operation + session) + raise error
- Snapshot. Before the mutation runs,
Snapshot::capture()records the target’s before-image andSafe_Mutationstores it, gzip-compressed, in thewp_wpmcp_snapshotstable, keyed by a generated operation ID (a UUID) and the calling session’s ID. - Apply. The tool’s actual mutation callback runs (e.g.
wp_update_post(),update_option(),wp_delete_post()). - Verify (optional, tool-specific). Some tools pass a verification callback.
update-blocks, for example, checks that the new block markup still parses as valid Gutenberg blocks. If verification fails,Safe_Mutationimmediately restores the snapshot and throws aMutation_Failedexception, so a bad write never survives past the same request. - Rollback, on demand. Separate from the automatic verify-and-revert above, any successfully-applied operation can be undone later via the
rollback-operationorrollback-sessiontools, or from the wpmcp wp-admin screen.
Every write tool returns an operation_id in its response specifically so a caller (human or agent) can reference it later for rollback.
What gets captured
Snapshot capture is dispatched by object type (src/Safety/Snapshot.php). The core types are post, option, user, comment, term and wc_order, and the integrations add their own (listed below). This is what makes product edits, order changes, comment edits, menu edits, page builder layouts and plugin data undoable through the same engine as posts and settings, not a separate one-off mechanism per domain.
Posts (and attachments, which are WordPress posts of type attachment):
- The full post row, every column from
get_post($id, ARRAY_A), not a hand-picked subset of fields. This matters for the resurrection path below: a partial capture would mean a force-deleted post comes back missing its original post type, author, parent, slug, dates, or menu order, silently rebuilt fromwp_insert_post()’s defaults. - All post meta (
get_post_meta($id)), every key and value. - Taxonomy term assignments, captured per taxonomy registered on that post type via
wp_get_object_terms(). - Comments and their comment meta, captured only for use by the force-delete resurrection path (see below). WordPress’s
wp_delete_post($id, true)destroys comments and commentmeta with no equivalent in the trash or in-place-update paths, so they have to be captured up front to be restorable.
A WooCommerce product is a post (post_type = product) and a navigation menu item is a post (post_type = nav_menu_item), so update-product, delete-product, update-menu-item, and remove-menu-item all restore exactly through this same full-row-plus-meta-plus-terms path: price, stock, description, title, url, parent, and position all come back as they were.
Options (used by update-settings and assign-menu-to-location):
- The option’s current value.
- Whether the option existed before the write. Options have no trash/soft-delete equivalent: a write either changes an existing value or introduces a brand-new option. Recording
existedlets rollback choose between putting the old value back (update_option()) or removing the option entirely (delete_option()) if it wasn’t there before.
Users (used by update-user):
- The user’s core profile fields and all usermeta, captured before any change so
rollback-operationrestores display name, email, url, nickname, name fields, and description exactly. Role and password are never touched by any wpmcp tool, so neither is part of this capture.
Comments (used by moderate-comment, edit-comment, and delete-comment):
- The comment row and its comment meta.
delete-comment‘s resurrection path reinserts the comment viawp_insert_comment(); the content, author, dates, and post association are restored, but (like force-deleted posts’ comments) the comment gets a new auto-increment ID, since WordPress core does not let a caller choose one.
WooCommerce orders (used by update-order-status):
- The order’s prior status, captured via the
wc_orderobject type so it is HPOS- and CPT-safe (it does not assume orders are stored as posts).rollback-operationrestores the exact prior status.
Integration snapshot types
- Page builders. WPBakery, Avada, Divi, Bricks, Beaver Builder, Breakdance, Oxygen 6, classic Oxygen and Thrive Architect all keep their layouts in
post_contentand post meta, so a builder write is an ordinarypostsnapshot and rolls back exactly. The rollback path then refreshes or invalidates the builder’s generated CSS the same way a forward write does. - WooCommerce (Pro catalog).
wc_order_full(a whole order, fororders.update),wc_shipping_zone(a whole zone with its methods),wc_webhook,wc_tax_rate, andoptionfor a payment gateway’s settings or a store setting. Creates record a creation row so rollback removes exactly what was created. - Plugin tables.
db_rowsfor a form entry’s status in the plugin’s own table (Gravity Forms, WPForms, Fluent Forms),plugin_table_rowsfor Pods table storage and TranslatePress dictionary rows,buddypress_rowsfor BuddyPress,redirection_itemfor Redirection redirects, andaioseo_rowfor All in One SEO. Restoring a raw table row is an administrator action. - Structure.
acf_structurefor ACF field groups, post types and taxonomies (keyed by the ACF key, so a create and its undo agree on what was created),acf_optionsfor ACF options pages,option_setwhen a theme settings write spans two options, andtheme_scaffoldfor a scaffolded child theme.
Some writes cannot be snapshotted and say so with recoverable: false rather than implying an undo that does not exist: a WooCommerce refund (the status comes back, the money does not), WooCommerce system status tools, the W3 Total Cache purge, and Forminator and SureForms entry deletes, which are also off by default.
Personal data in snapshots
A snapshot is a verbatim before-image, so some snapshots hold personal data. wpmcp treats restoring one as the same privilege as reading it:
- Comments and reviews. Restoring a comment snapshot needs
moderate_comments, the capability that reading a commenter’s email and IP takes; restoring a product review also needsedit_producton its product. Change sets and the history screen never show a commenter’s email, IP address or browser details. - Posts with comments. Rolling back a deleted post as a user without
moderate_commentsbrings the post and its comments back, with each commenter’s email, IP and user agent left blank, and the rollback response says so. - Other personal data. A payment gateway settings snapshot holds its credentials, so restoring it takes
manage_woocommerce. A Flamingo entry snapshot takesedit_users. BuddyPress and raw table snapshots takemanage_options. - Reversible is not erased. Because a deleted form entry can be restored, a copy stays in the snapshot history until it is pruned. A reversible delete is not a GDPR erasure, and the ops that do it say so.
Rollback on shared data
Some objects keep changing after an agent writes to them, because other people use the site. BuddyPress is the clearest case: members join groups, reply to activity and trigger notifications. A BuddyPress write records every row it and BuddyPress’s own hooks created, and its rollback restores only the rows it saved, by id. It removes only the rows the write itself created, keeps membership requests, notifications and replies that other members added after the write, keeps reply numbering in a thread consistent, and leaves in place, and reports, any created row that has since changed hands. The same principle applies elsewhere: rolling back a WooCommerce shipping zone create removes the zone only while it is still the zone that was created, and undoing a Redirection create never removes a different redirect that took its place.
Snapshots are serialized with gzencode(wp_json_encode($before)) and stored in a LONGBLOB column.
Operation rollback vs session rollback
Two distinct undo scopes, both backed by the same snapshot table:
rollback-operationrestores exactly one snapshot, identified by itsoperation_id. Simple: look up the row, apply that snapshot.rollback-sessionunwinds an entire agent session. It pulls every snapshot recorded under asession_id, walks them oldest-first, and for each distinct object restores only the earliest snapshot seen, that object’s state from before the session touched it at all. If the same post was edited three times in one session, only the first (pre-session) snapshot is applied; the two later ones are skipped once the object’s identity has already been restored. The tool’s return value (restored_count) counts snapshot rows processed, not distinct objects restored, so it can be larger than the number of objects that actually changed.
Object identity for deduplication is object_type:object_id for posts, users, comments, and orders, and option:<option name> for options (the raw database object_id column is always 0 for option rows, since options are identified by name, not a numeric ID; the real name lives inside the serialized blob).
The meta-purge
Rollback is a full restore, not an additive merge. If the mutation being undone added a new meta key that did not exist at snapshot time, a rollback that only restored the snapshotted keys would leave that new key behind as orphaned meta, i.e. the object would not be truly back to its pre-mutation state.
To prevent that, Rollback_Service::apply_snapshot():
- Diffs the object’s current meta against the snapshotted meta.
- Deletes any meta key present now but absent from the snapshot (added by the mutation being undone).
- Deletes and re-adds every snapshotted key/value pair exactly as captured.
This is what makes rollback exact rather than approximate: a restored object matches its pre-mutation state, including the absence of anything the agent added.
Force-delete and resurrection, with ID verification
Trashing a post (delete-post without force: true) is not routed through Safe_Mutation at all: WordPress’s own trash already makes it reversible, so a redundant snapshot would buy nothing. Force-deleting (force: true) permanently removes the post row, so that path is safe-wrapped.
When a force-deleted post needs to be rolled back, the row no longer exists, so a plain wp_update_post() would silently no-op. Instead, Rollback_Service re-inserts the post at its original ID using wp_insert_post()’s import_id parameter, then replays the captured comments on top of it via wp_insert_comment() (comment IDs themselves cannot be preserved, WordPress core always assigns a new auto-increment comment ID, but content, author, dates, and thread association with the post are restored).
Two safety checks guard this resurrection path:
- Identity check before choosing the restore path. If a post already exists at the target ID, wpmcp does not assume it’s safe to just update it in place. It compares
post_date_gmt(immutable after creation) between the live row and the snapshot. If they don’t match, the row at that ID is a different post that has since reclaimed the ID (e.g. someone manually re-imported content after the original was force-deleted), and blindly updating it would silently overwrite an unrelated post. In that case rollback routes through the resurrection path instead, which triggers the next check. - ID collision check after resurrection.
wp_insert_post()’simport_idis only honored if that ID is still free; on a collision it silently falls back to a new auto-increment ID instead of erroring. wpmcp checks the returned ID against the ID it asked for, and if they don’t match, throws aMutation_Failedrather than leaving a “restored” post sitting at the wrong ID with no error. A rollback that silently succeeds at the wrong ID would be worse than one that fails loudly.
Known limitations, stated honestly
Free-tier history retention bounds session rollback, by whole runs. Snapshot_Store::history_limit() returns 20 by default; the wpmcp_snapshot_history_limit filter raises or lowers that number on any site at no cost, and the Pro build adds that filter itself, returning unlimited (PHP_INT_MAX) while the licence is active. After every write, Safe_Mutation::run() calls Snapshot_Store::prune(), which trims the table back toward that limit. Pruning is session-aware: a bulk run recorded under one session is kept or dropped as a whole, never cut in the middle, and the most recent run is always kept whole however large it is, so it stays fully undoable with rollback-session. A single write that would itself exceed the limit holds pruning until it finishes, and the next write outside the hold prunes as usual, by whole sessions. What the cap means in practice on a free-tier site: once newer runs have pushed an older session out of the table, rollback-session for that session is refused with the reason, instead of silently undoing only the part that survived. Pro sites keep every session while the licence is active, and if a licence ends the history is held at its current depth until the owner trims it or sets a depth, so a lapse never deletes undo points on its own.
Media force-delete does not restore file bytes. Force-deleting an attachment (or deleting one without MEDIA_TRASH defined) permanently unlinks the physical file from disk. Rollback via Safe_Mutation restores the media’s database record faithfully, the post row, all meta, and taxonomy terms, but it cannot restore bytes already deleted from the filesystem. The delete-media tool response signals this explicitly with "files_recoverable": false and a warning field pointing at the tracking issue. Full file-level recovery is tracked as issue #24 and is not yet implemented. Because of this, delete-media is disabled by default: a site must opt in via the wpmcp_enable_delete_media filter, and every call additionally requires confirm: true.
Note on wording: an earlier design-spec draft stated that snapshot capture does not record taxonomy terms. That is now out of date. The current Snapshot::capture() implementation does capture per-taxonomy term assignments for posts, and Rollback_Service::apply_snapshot() restores them via wp_set_object_terms(). What is genuinely not yet captured is a small set of secondary post fields not covered by the full-row capture’s practical use today (the design intentionally captures the entire row, so this gap is narrower than earlier drafts suggested); consult src/Safety/Snapshot.php directly if you need the exact current field list, since this is an area still evolving.
Driving rollback
- From an agent: call the
rollback-operationorrollback-sessionMCP tools directly (see Tools reference). - From a human: open the wpmcp screen in wp-admin, which lists recent operations (via the same
list-operationsdata) with a one-click Restore button per row.
Tools Reference
WP MCP currently registers 407 abilities in the canonical test environment: 274 free and 133 Pro. Every tool below is registered as a WordPress ability named wpmcp/<tool-name> via the official Abilities API, each with its own permission_callback (content tools require edit_posts; sensitive domains are gated by stronger capabilities).
Every mutating tool routes through Safe_Mutation::run(), so it is snapshotted before it runs and can be undone with rollback-operation or rollback-session, except the small set of deliberately risky operations that are disabled by default and honestly say so in their descriptions. See The safety model for how the engine works.
This page is generated from the plugin source and its ability manifest; the descriptions below are the exact ones the AI agent sees.
Safety & history (3 tools)
list-operations: List recent safety snapshot operationsrollback-operation: Undo a single operation by restoring its pre-change snapshotrollback-session: Undo all operations from a session by restoring each object’s pre-session snapshot
Content & pages (16 tools)
count-content: Counts so a job can be sized before it starts: posts per public type by status, media by MIME family, comments by status, terms per taxonomy, users per role. From core counting APIs, so figures match wp-admincreate-post: Create a post, page, or custom post typedelete-post: Delete a post, page or CPT entry. Trash by default (reversible). force:true deletes permanently, is off until the wpmcp_enable_delete_post filter opts in, needs confirm:true, and is snapshotted (undoable)diff-revisions: Diff two revisions of a post, or one revision against the post’s current state: a unified diff per changed field (title, content, excerpt) rather than two full documents. Unchanged fields are omittedduplicate-post: Copy a post, page or CPT entry (content, meta but _edit_lock and _wp_old_slug, terms, builder data; children optional) as a draft unless status is set. stage:true: one linked draft to edit; publish_stage:writes it over the original (same ID, URL, comments; refused if the original changed, unless force; undo: rollback-operation); discard_stage deletes it get-page: Read a pageget-post: Read a single post, page, or custom post typeget-revision: Read a single post revision’s fieldslist-post-types: List registered post types (posts, pages, custom post types)list-posts: List/search posts, pages, or custom post typeslist-revisions: List a post’s revisions (id, author, date, change excerpt)list-taxonomies: List registered taxonomies (categories, tags, custom taxonomies)restore-revision: Restore a post to a given revisionset-post-terms: Assign taxonomy terms to a post (replace, append, or remove)update-blocks: Update a page’s block contentupdate-post: Partially update a post, page, or custom post type
Taxonomy terms (6 tools)
create-term: Create a category, tag or custom taxonomy term. Snapshot-first; rollback-operation reverses the creation. Refuses an existing slug, a missing parent, or a parent on a non-hierarchical taxonomydelete-term: Delete a term, snapshot-first. Rolling back restores it at its original term_id and term_taxonomy_id and refiles the posts that were in it. Reports objects affected; refuses a taxonomy’s default termget-term: Read one term by term_id or slug, with its meta and full ancestor chain. Ancestors disambiguate a hierarchical taxonomy, where several same-named terms sit under different parentslist-terms: List terms in a taxonomy with search, parent filter, ordering and pagination. Empty terms are INCLUDED unless hide_empty is set (the opposite of core’s default), so a partial list never leads to creating a duplicateset-term-meta: Write or delete a term meta value, snapshot-first (whole term plus meta map captured, so rollback is exact). value:null deletes the key, staying distinct from an empty string. Protected keys are refusedupdate-term: Update a term’s name, slug, description or parent, snapshot-first. Refuses a slug held by another term, and refuses reparenting onto itself or a descendant: core permits that and the resulting cycle makes the taxonomy unrenderable
Site content search (2 tools)
reindex-search: Build or rebuild the search-content index. The index updates on save; use this for the first build or after bulk or out-of-band changes. Cursor-based: each call indexes up to batch_size posts and returns next_offsetsearch-content: Search all site text, incl. what post_content search misses: Elementor and Bricks settings, block attributes, template parts, reusable blocks and nav menus. Each hit has a location (block path, element id or menu item id) and a snippet. Read-only; hits re-checked against read_post. Empty index: run reindex-search
Gutenberg blocks (5 tools)
convert-html-to-blocks: Convert raw HTML to Gutenberg block markup: h1-h6, p, img, ul/ol, blockquote, pre/code, hr and table map to core blocks; anything else is wrapped in core/html so nothing is lost. Pure transform, never touches a post; write it with update-blocksget-block-type: Return full detail for a single registered block type by name: its attributes schema, declared supports and block-context wiring (uses_context, provides_context)list-block-types: List registered block types: name, title, category, is_dynamic and attribute names. Optional category (exact) and search (substring on name) filtersparse-blocks: Parse block markup into its block tree via parse_blocks(). Takes “blocks” (raw markup) or “id” (parses that post’s post_content). Each node reports blockName, attrs, recursively parsed innerBlocks, and an innerHTML summaryserialize-blocks: Serialize a block tree (parse-blocks shape) back into block markup via serialize_blocks(). A pure transform that never touches a post; write the result with update-blocks
Surgical block edits & patterns (7 tools)
add-block: Insert ONE block (“” markup) into a post at path (zero-based indexes into the parse-blocks tree; the last may equal the sibling count to append). Needs expected_hash (content_hash from parse-blocks); stale reads refused. Snapshot-first; other blocks stay byte-identicalduplicate-block: Duplicate the block at path (deep copy, inserted immediately after the original within the same parent) and return the copy’s new_path. Needs expected_hash (content_hash from parse-blocks); stale reads refused. Snapshot-firstinsert-pattern: Insert a registered block pattern’s blocks into a post at path (add-block’s path semantics; whitespace filler dropped). Needs expected_hash (content_hash from parse-blocks); stale reads refused. Snapshot-first; existing blocks stay byte-identicallist-patterns: List registered block patterns: name, title, description, categories. Optional search (substring on name or title). Markup is not returned; insert-pattern inserts it server-sidemove-block: Move the block at from_path to position to_index among its own siblings (same parent only; compose remove-block + add-block to move across parents). Needs expected_hash (content_hash from parse-blocks); stale reads refused. Snapshot-firstremove-block: Remove ONE block by path (zero-based indexes into the parse-blocks tree, descending innerBlocks); nested removals keep the container. Needs expected_hash (content_hash from parse-blocks); stale reads refused. Snapshot-first; undo: rollback-operationupdate-block: Update ONE block by path (zero-based indexes into the parse-blocks tree, through innerBlocks): replace attrs (whole) and/or inner_html (leaf blocks only; a container’s children by their own paths). Needs expected_hash (content_hash from parse-blocks); stale reads refused. Snapshot-first; other blocks stay byte-identical
Composite page builds (1 tool)
build-page: Compose a complete page from ONE declarative spec: title, a recursive sections/blocks tree, media references (existing attachment ids), and optional menu placement. The whole composition is a single atomic, recoverable operation: the spec is strictly validated (node-path-addressed errors, bounded size/nodes/depth) before any write, a mid-build failure automatically removes everything it created, and on success one operation_id is returned whose rollback-operation removes the page and its menu placement entirely. Markup is composed deterministically from the spec; nothing in the spec is evaluated or executed. dialect “gutenberg” (default, free) builds block markup; dialect “elementor” (PRO, requires Elementor) builds an _elementor_data element tree. Set dry_run=true to validate and compose WITHOUT writing: the reply reports element counts per node type, nesting depth, markup size, unknown widget types, atomic props that had to be coerced, and every referential problem at once
Custom block builder (8 tools, 8 Pro)
create-custom-block, Pro: Create a custom Gutenberg block from a data spec (title, attributes, template with {{name}} placeholders). Validated, stored as a wpmcp_block post and registered at runtime; a render_callback interprets the template (no code generation, no eval). Remove with delete-custom-blockdelete-custom-block, Pro: Delete a custom block by moving it to the trash. Snapshotted: returns an operation_id for rollback-operation (restore-post also works)get-custom-block, Pro: Read one custom block’s stored spec by idlist-block-control-types, Pro: List the attribute types a custom-block spec may use and the block.json type each maps tolist-custom-blocks, Pro: List the custom blocks on this site (id, name, title, active/inactive)set-block-status, Pro: Enable (publish) or disable (draft) a custom block by id. Snapshotted: returns an operation_id for rollback-operation; a no-op status change writes nothingupdate-custom-block, Pro: Replace a custom block’s spec by id (re-validated before it is stored). Snapshotted: returns an operation_id for rollback-operationvalidate-block-spec, Pro: Statically validate a custom-block spec (title, attributes, template) without storing it
Media library & stock images (12 tools, 1 Pro)
delete-media: Delete a Media Library attachment. Off until the wpmcp_enable_delete_media filter opts in; needs confirm:true. force:true deletes permanently, snapshotted (undoable)get-media: Read a Media Library attachment: title, URL, every registered size, dimensions, mime type, alt text, caption and descriptionimport-stock-image: Sideload a stock search result into the Media Library. SSRF-guarded: https only, host allowlist (wpmcp_remote_media_allowed_hosts filter) checked first, no redirects, size caps, bytes must verify as an image. Stores attribution and license. Undo: rollback-operationinsert-stock-image, Pro: Run import-stock-image’s SSRF-guarded import, then insert the image into the post’s builder content as a Gutenberg image block. Returns two operation ids, each undoable on its own (insert, import)list-media: List Media Library attachments, filtered by type (“image” or a mime like “image/png”), after/before dates and search, paged newest first with total/pagesresize-media: Regenerate the given registered image sizes of an attachment from its original and report each file (name, dimensions, URL). Snapshot-first with a file backup (undoable)search-stock-images: Search openly-licensed stock images: openverse (keyless, Creative Commons), pexels and unsplash (own key via set-stock-key). Results carry license, license_url, attribution and source_url for import-stock-imageset-stock-key: Store (or clear with an empty api_key) your own pexels or unsplash API key. Keys are encrypted at rest with a site-salt-derived key and never echoed backsideload-image: Add an image to the Media Library from a url, or from a prompt via the site’s AI provider (ratio e.g. 16:9). Undo: rollback-operationupdate-media: Update an attachment’s title, alt text, caption or descriptionupload-media: Upload a file to the Media Library from base64 data, an https url, or grant:true (returns a one-use upload URL and curl, for large files). Type sniffed from the bytes, not mime_type; executables and SVG refused; capped at the upload limit. Undo: rollback-operationupload-svg: Add an SVG to the Media Library from markup or an allowlisted URL. A fail-closed sanitizer rejects script, foreignObject, event handlers and external references; only sanitized markup is stored. Rollback deletes it
Options & post meta (4 tools)
get-option: Read a single wp_options value by name. Refuses a conservative denylist of sensitive/core option names (auth keys and salts, siteurl, home, active_plugins and secret/password/token-shaped names)get-post-meta: Read a post’s meta, either the full map or a single key. Protected meta (a leading underscore, or is_protected_meta) is always skippedset-post-meta: Set a single meta key/value on a post. Refuses protected meta keys (a leading underscore, or is_protected_meta). Snapshotted via object_type post; rollback-operation restores the prior valueupdate-option: Update one wp_options value by name. Refuses get-option’s denylist; off until the wpmcp_enable_option_write filter opts in. Snapshotted; rollback-operation restores the prior value or removes a new option
Site settings (2 tools)
get-settings: Read WordPress site settings (general, reading, writing, discussion, media, permalinks), each with its group, type and whether it is writableupdate-settings: Update WordPress site settings from a strict allowlist. Validates/coerces each value (enum, int range, bool), rejects unsafe permalink structures, skips read-only or non-allowlisted keys and still applies the valid subset
Users (4 tools)
create-user: Create a new non-admin user. Auto-generates a strong password (never returned) and emails the new user so they can set their own. Rejects admin and unknown roles; defaults to subscriberget-user: Read one user’s profile detail, including an is_admin flag derived from live capabilities. Never returns the password hashlist-users: List WordPress users as safe summary rows (id, username, display name, email, roles, registration date). Never returns password hashes or other secretsupdate-user: Update a non-admin user’s profile fields (display name, email, url, nickname, first/last name, description). Refuses admin-capable users. Never changes role or password. Snapshotted so the change can be rolled back
Comments (5 tools)
delete-comment: Permanently delete a comment. Off until the wpmcp_enable_delete_comment filter opts in; needs confirm:true. Rollback restores it under a new IDedit-comment: Edit a comment’s content or author name, email, url. Reversibleget-comment: Read one commentlist-comments: List comments, optionally by post and status, with pagingmoderate-comment: Set a comment’s status: approve, unapprove, spam, trash or untrash. Reversible
Navigation menus (9 tools)
add-menu-item: Add an item to a navigation menu (custom link by title and url, or an object link via type, object, object_id). Additive; a mistaken item can be removed with remove-menu-itemassign-menu-to-location: Assign a navigation menu to a registered theme location (the nav_menu_locations theme_mod). Snapshotted; rollback-operation restores the prior assignmentcreate-menu: Create a new navigation menu (a nav_menu term). Creation has no prior state to snapshot; a mistaken menu can be removed with delete-menudelete-menu: Delete a navigation menu (a nav_menu term). Off until the wpmcp_enable_delete_menu filter opts in; needs confirm:true. Not automatically reversible: the menu name and items are returned for a manual rebuildget-menu: Read one navigation menu with its ordered items (id, title, url, type, parent, order)list-menu-locations: List the theme’s registered menu locations and the menu (if any) assigned to eachlist-menus: List the site’s navigation menus as safe summary rows (id, name, slug, item count)remove-menu-item: Remove an item from a navigation menu. Snapshotted as a post; rollback-operation resurrects it at its original id, re-attached to its menuupdate-menu-item: Update a navigation menu item’s title, url, parent, or position. Snapshotted as a post; rollback-operation restores the prior values exactly
Plugins & themes (13 tools)
activate-plugin: Activate an installed plugin. Snapshots the prior active_plugins option (undoable)deactivate-plugin: Deactivate a plugin. Refuses protected packages (wpmcp, Elementor). Snapshots the prior active_plugins option (undoable)delete-plugin: Permanently delete an installed plugin’s files. Disabled by default (wpmcp_enable_delete_plugin filter) and needs confirm:true. Refuses protected or active plugins. Not rollback-abledelete-theme: Permanently delete an installed theme’s files. Disabled by default (wpmcp_enable_delete_theme filter) and needs confirm:true. Refuses the active theme (or its active parent). Not rollback-ableget-plugin-info: Fetch full wordpress.org plugin directory info for a slug: version, rating, installs, homepage, download link and compatibilityinstall-plugin: Install a plugin from wordpress.org by slug. activate: true also needs activate_plugins and returns a rollbackable operation_idinstall-theme: Install a theme from wordpress.org by slug. activate: true also needs switch_themes and returns rollbackable operation_idslist-plugins: List installed plugins with active status, protected-package flag and pending update info; updates:true lists core, plugin and theme updates with auto-update statelist-themes: List installed themes with active status, parent theme and pending update infosearch-plugins: Search the wordpress.org plugin directory by keyword, with optional tag/author filters and a capped per_pageswitch-theme: Activate an installed theme. Snapshots the prior template/stylesheet options (undoable)update-plugin: Update an installed plugin to the latest wordpress.org version. Disabled by default (wpmcp_enable_update_plugin filter) and needs confirm:true. File changes are not rollback-ableupdate-theme: Update an installed theme to the latest wordpress.org version. Disabled by default (wpmcp_enable_update_theme filter) and needs confirm:true. File changes are not rollback-able
Theme builder (headers, footers, 404) (6 tools)
create-site-part: Create a header, footer or 404 site part, shown where an include rule matches and no exclude rule does; not the Elementor theme-template tools. Capped per part type; wpmcp/delete-site-part frees a slotdelete-site-part: Trash a site part, freeing its per-part-type slot. Snapshot-first: operation_id rolls it backlist-site-parts: List site parts with their conditions and status, optionally by part_typeresolve-site-part: Which site part wins for a context (most specific, then priority), with every candidate and why. post_id alone fills post_type and term_idsset-site-part-status: Activate (publish) or deactivate (draft) a site part; only active parts resolve. Snapshot-firstupdate-site-part: Edit a site part; omitted fields are kept, part_type is fixed. Snapshot-first: operation_id rolls it back
Custom CSS & JavaScript (2 tools, 2 Pro)
add-custom-js, Pro: Store the site-wide JS snippet printed in wp_footer (replaces the previous one; js=“” + replace=true clears). XSS-CLASS SURFACE, off by default: needs WPMCP_ALLOW_JS_INJECTION or wpmcp_allow_js_injection, plus unfiltered_html and manage_options. Snapshot-first; closing the gate stops rendering stored JSadd-scoped-css, Pro: Store CSS printed in wp_head only on one post/page (post_id required). Pass css, or selector plus bare declarations; element_id (Elementor) scopes it to .elementor-element-. Appends; replace=true overwrites, css=“” + replace=true clears. Site-wide: add-custom-css. Needs edit_css and manage_options. Refuses script-capable CSS (markup, expression(), script or data: URLs, @import), even obfuscated. Snapshot-first per page
WooCommerce (32 tools, 3 Pro)
add-order-note: Add an internal or customer-facing note to a WooCommerce order. Additive only; nothing to roll backapply-product-import: Apply a plan-product-import plan: same rows and mode plus its plan_hash. Refused if the store or rows changed; confirm:true above the threshold. rollback-session on its session_id undoes itbulk-update-products: Update up to 50 products and variations in one call; each item {id, …fields} as update-product/update-variation take them, same rules and permission checks. Per item: ok, operation_id or error; one failure does not stop the rest. rollback-session on the returned session_id undoes the batchcreate-coupon: Create a coupon. Refuses a code already in use, an unknown discount_type, a percent over 100 or an invalid email restriction. Status defaults to draft. Undo with delete-couponcreate-product: Create a simple WooCommerce product via the CRUD layer. Creation has no prior state to snapshot; a mistaken product can be removed with delete-productcreate-tax-rate: Create a tax rate. rate is a percentage from 0 to 100; country must be a known ISO code or “” for all; class must be standard or an existing class. Undo with delete-tax-ratecreate-variation: Add a variation to a variable product. attributes maps each variation attribute to one of its options (“” or omitted = any); unknown attributes or options are refused. Prices, sku, status and stock follow update-variation’s rules. Undo with delete-variationdelete-coupon: Delete a coupon (trash by default, force for permanent). Disabled until the site opts in via the wpmcp_enable_delete_coupon filter; needs confirm:true. Snapshotted: rollback-operation restores it at the same iddelete-product: Delete a WooCommerce product (trash by default, force for permanent). Off until the wpmcp_enable_delete_product filter opts in; needs confirm:true. Snapshotted: rollback resurrects a force-deleted product at its id with price, stock and termsdelete-tax-rate: Delete a tax rate. Disabled until the site opts in via the wpmcp_enable_delete_tax_rate filter; needs confirm:true. Snapshotted: rollback-operation restores it at the same iddelete-variation: Permanently delete a product variation (there is no variation trash). Disabled until the site opts in via the wpmcp_enable_delete_variation filter; needs confirm:true. Snapshotted: rollback-operation resurrects it at the same id, attached to its parentget-coupon: Read one coupon’s full settings by id or code (limits, restrictions, usage)get-order: Read full detail for one WooCommerce order (status, billing email, payment method, line items, customer note). HPOS- and CPT-safeget-product: Read full detail for one WooCommerce product (prices, stock, description, categories, tags)get-sales-report: Read-only sales summary over a date range: order count, gross sales, items sold and top products by quantity. Aggregated over wc_get_orders() (HPOS- and CPT-safe)list-coupons: List coupons as summary rows (id, code, status, type, amount, usage, expiry), with code search, status filter and paginglist-low-stock-products: List products and variations at or below a managed-stock threshold (default: the store’s low-stock setting) or out of stock, as rows whose ids feed update-product/update-variation. Page while has_more is truelist-orders: List WooCommerce orders as safe summary rows (id, number, status, total, currency, date), filterable by status and customer, with paging. HPOS- and CPT-safelist-product-categories: List WooCommerce product categories (the product_cat taxonomy) as summary rows (id, name, slug, parent, count)list-products: List WooCommerce products as safe summary rows (id, name, sku, price, stock status), filterable by search, status, type, or category, with paginglist-tax-rates: List the store’s tax classes and tax rates, filterable by class or country, with paging. Read-onlylist-variations: List the variations of one variable WooCommerce product as safe summary rows (id, sku, attributes, prices, stock), with pagingplan-product-import: Plan a product import; writes nothing. Rows: sku, name, type (simple/variable), regular_price, sale_price, stock, categories, attributes, variations, images (media ids or https URLs), status. Per row: create, update (diff), skip or error; plus a plan_hashupdate-coupon: Update a coupon’s fields with the same checks as create-coupon. Snapshotted: rollback-operation restores every setting and usage historyupdate-order-status: Change a WooCommerce order’s status, validated against the store’s registered statuses. Snapshotted via the wc_order object type so rollback-operation restores the prior status exactly. HPOS- and CPT-safeupdate-product: Update a WooCommerce product’s fields (price, stock, description, etc.). stock_status is accepted only while stock is unmanaged and never on a variable product. Snapshotted as a post; rollback-operation restores the prior price and stock exactlyupdate-tax-rate: Update a tax rate with the same checks as create-tax-rate; postcodes and cities replace the whole list. Snapshotted: rollback-operation restores the row and its locationsupdate-variation: Update a WooCommerce variation: regular_price, sale_price, sku, status (publish/private), manage_stock, stock_quantity and stock_status (only while stock is unmanaged). Snapshotted; rollback-operation restores price and stock, keeps it attached to its parent and re-syncs the parent’s price rangevalidate-coupon: Check whether a coupon code would be accepted: published, expiry, usage limits, and (when email or subtotal is given) per-customer limit, email allow-list and spend rules. Each rule reports pass, fail or skipped; cart-dependent rules are flaggedwoo-ops, Pro: List WooCommerce ops (e.g. orders.get) by domain: products, variations, orders, refunds, coupons, customers, reviews, reports, shipping, taxes, webhooks, settings, gateways, system-status. Each op: mode, route, path params, capability, confirm, enabled, snapshot type, full-rollback flag. Read-onlywoo-read, Pro: Run one read op from woo-ops as an in-process wc/v3 request as the current user, gated by op capability and governance (wpmcp/woo-{op}, dots as dashes). Path params fill the route, the rest are query. Returns the raw wc/v3 body (may include personal data; secrets redacted); 20 per page, max 50. Read-onlywoo-write, Pro: Run one woo-ops write op or a batch of up to 25 as in-process wc/v3 requests as the current user, gated like woo-read. Path params fill the route, the rest are the body (query for deletes). Changes to existing state are snapshotted (operation_id for rollback-operation); creates return recoverable:false and an undo_op. Refunds are not recoverable and call the gateway only with api_refund:true. Deletes and refunds need the wpmcp_woo_op_enabled filter and confirm:true. A batch prechecks every item, refuses whole on any failure and shares one session_id for rollback-session
SEO metadata (5 tools)
get-crawler-files: robots.txt (served output, physical file, managed rules), llms.txt, and the served sitemap (core or SEO plugin) with its post typesget-seo-meta: Read a post’s SEO title, meta description, focus keyword, canonical URL, and robots flags (noindex/nofollow) via the active SEO plugin’s postmeta keysget-seo-status: Which SEO plugin is active, by name and versionupdate-crawler-files: Add robots.txt rules (filter, never the file), build llms.txt from pages, or exclude post types, taxonomies or posts from the core sitemap (lists replace). Refused if a physical file or the SEO plugin owns it. Snapshottedupdate-seo-meta: Set a post’s SEO title, meta description, focus keyword, canonical URL and/or robots flags (noindex/nofollow) via the active SEO plugin’s postmeta keys. Snapshotted as a post; rollback-operation restores the prior values exactly
SEO depth: term SEO, social meta, schema (6 tools, 6 Pro)
generate-meta-tags, Pro: Propose a post’s title, description, canonical, robots, OpenGraph and Twitter tags from SEO plugin fields or the post record, each with its source. Read-only proposalgenerate-schema-markup, Pro: Generate schema.org JSON-LD (Article, WebPage, LocalBusiness or Product) for a post from title, dates, author, excerpt or SEO description, featured image, permalink and, for Product, the WooCommerce record. Proposal only: writes nothingget-social-meta, Pro: Read a post’s OpenGraph and Twitter overrides (title, description, image) from the active SEO plugin as one field set. Plugins with unmapped social storage return a structured unsupported responseget-term-seo-meta, Pro: Read a term’s SEO fields (as get-seo-meta) by taxonomy plus term_id or slug. Fields the plugin lacks on terms are in unsupported_fields; no term storage returns supported:falseset-social-image, Pro: Set a post’s OpenGraph and/or Twitter image from an attachment_id or image_url via the active SEO plugin. Snapshotted, undo with rollback-operation. Unmapped plugins return supported:falseupdate-term-seo-meta, Pro: Set a term’s SEO fields (as update-seo-meta) by taxonomy plus term_id or slug. Snapshotted; rollback-operation undoes it. Fields the plugin lacks on terms return in skipped_fields
Redirects & broken links (5 tools)
create-redirect: Create a managed redirect from a source path to a target URL or target_post_id (which survives slug changes). Chains are flattened to one hop and loops refused; the stored target is reported. Snapshotted; rollback-operation removes itdelete-redirect: Delete one managed redirect. The whole row is snapshotted first, so rollback-operation brings the same redirect back; use update-redirect with enabled:false instead to stop it firing while keeping its hit historyfind-broken-links: Scan published content for internal links that are dead, point at a non-public post or go through a redirect. background:true queues a batched scan; poll it with scan_id. Proposes fixes, changes no contentlist-redirects: List this site’s managed redirects (source path, resolved target, status code, enabled, hit count), plus pending suggestions raised when a published post was deleted or moved. Filter by enabled state or a search string. Read-onlyupdate-redirect: Change one managed redirect: its source, target/target_post_id, status code, enabled state or notes. Only the fields you pass change. Retargeting re-runs chain flattening and loop detection. Snapshotted and reversible
Internal linking (3 tools)
find-orphan-posts: List published posts or pages that have zero incoming internal links (orphans), by scanning the most-recent posts for links that resolve to this site’s own contentget-link-map: Summarize the internal-link graph: per-post outgoing and incoming link counts, the orphan list and the most-linked postssuggest-internal-links: Suggest related published posts a given post should link to, ranked by shared categories/tags and title keyword overlap, excluding posts it already links to
Content analysis (accessibility, SEO, contrast) (8 tools, 8 Pro)
add-alt-text-from-context, Pro: Write missing image alt text in a post from filename, nearest heading or title. Keeps existing alt unless overwrite_existing=true; skips decorative images. Dry run unless apply=true; one snapshot, one rollbackanalyze-accessibility, Pro: Scan a post’s HTML for WCAG issues (missing alt text, heading jumps, empty or vague link text, unlabeled form controls): scored findings with element locations. Read-onlyanalyze-seo, Pro: op score (default; post_id): on-page SEO 0-100 with findings (title/meta length, headings, words, alt, links, keyword density, readability). op keywords: volume, difficulty, CPC, intent. op backlinks (target domain or URL): link counts. Both use your provider key (set-seo-data-key), cached. Read-onlycheck-contrast, Pro: WCAG contrast ratio of a foreground/background hex pair, with AA/AAA pass/fail for normal and large text. Read-onlyextract-content, Pro: A post’s plain text and structure (headings, word count, link and image counts). keywords=N adds the top N terms and 2-3 word phrases, title and headings weighted. Read-onlyfix-color-contrast, Pro: Raise failing inline text/background color pairs in a post to a target WCAG ratio by lightness only (hue kept); before/after color, ratio, level per pair. Dry run unless apply=true; one snapshot, one rollbackfix-link-text, Pro: Replace empty or generic internal link text (“click here”, “read more”) with the destination title (WCAG 2.4.4, SEO). Skips external links and anchors with markup. Dry run unless apply=true; one snapshot, one rollbackset-seo-data-key, Pro: Save SEO data provider credentials for analyze-seo (empty api_key clears); dataforseo: “login:password”. Encrypted, never echoed
Elementor catalog (free) (4 tools)
get-global-settings: Read the Elementor kit’s global colors, typography, spacing and layout. Returns the settings_hash the global color and typography writes requireget-widget-schema: The settings schema for one Elementor widget type: curated typed params (defaults, enums, responsive hints, required plugin) for cataloged widgets, or with full:true (and for non-cataloged widgets) the full introspected control stacklist-widgets: List Elementor registered widget types (name, title, categories, icon, tier, availability), annotated from the curated catalog (purpose, cataloged flag). Filter by tier (free/pro), category or case-insensitive search (name, title, catalog keywords)regenerate-elementor-css: Rebuild Elementor CSS; all needs confirm
Elementor deep editing (33 tools, 33 Pro)
add-custom-css, Pro: Add site-wide custom CSS via core Additional CSS, so it works on any site (Elementor Pro not required). Appends, or replaces with replace=true. Snapshot-first when the Additional-CSS post exists (undo: rollback-operation)add-widget, Pro: Add a widget to a page’s _elementor_data under parent_id (or top level) at an optional position. Cataloged widget_types (list-widgets) take typed params validated before any write; other registered widgets take raw settings. Needs expected_hash from get-elementor-data. Undo: rollback-operationapply-template, Pro: Copy a library template’s content into a page with fresh ids that never collide, appended (default, optionally under parent_id at position) or replacing the whole page (mode=replace). Needs expected_hash from get-elementor-data. Undo: rollback-operationcreate-code-snippet, Pro: Create an Elementor Custom Code snippet (elementor_snippet post). location: wp_head, wp_body_open or wp_footer. Stored on any site; renders where Elementor Pro Custom Code is active. Not snapshotted (creates only); remove with delete-code-snippetcreate-popup, Pro: Create an Elementor popup (elementor_library post, type popup), optionally seeded with elements and trigger/display settings. Not snapshotted (creates only); configure further with set-popup-settings, remove with delete-postcreate-theme-template, Pro: Create an Elementor theme-builder template: a header, footer, single, archive, loop-item, search-results or error-404 elementor_library post, optionally seeded with elements and display conditions. Not snapshotted (creates only); remove with delete-theme-templatedelete-code-snippet, Pro: Delete an Elementor Custom Code snippet by moving it to the trash (reversible through WordPress trash / restore-post), mirroring the default delete-post pathdelete-theme-template, Pro: Delete an Elementor library template by moving it to the trash (reversible through WordPress trash / restore-post), mirroring the default delete-post pathdetect-elementor-version, Pro: Report the Elementor and Elementor Pro versions, supports_atomic (Elementor 4.0+) and atomic_tools_registered: the four atomic write tools register only on a builder that renders atomic elements, so check before assuming they existexport-page, Pro: Export a page’s Elementor content to a portable structure (content element tree + page_settings + type + version), the envelope import-template accepts, so a design can move between pages or sitesexport-template, Pro: Export an elementor_library template as the portable envelope import-template accepts (element tree, page_settings, conditions, type, version), so it round-trips between sites intactgenerate-widget, Pro: Generate a widget of any cataloged type (list-widgets / get-widget-schema) into a page’s _elementor_data under parent_id or top level, with a seedable element id. Unknown types and invalid settings are refused before any write. Undo: rollback-operationget-custom-css, Pro: Read the site’s WordPress core Additional CSSget-elementor-data, Pro: A page’s parsed Elementor tree (id, elType, widgetType, settings, children). Large pages: summary=true (skeleton with labels and child/descendant counts), max_depth (cut nodes report truncated_children) or element_id for one subtree. Reports total/returned_elements, truncated; data_hash covers the whole page, so windowed reads are a valid expected_hashget-theme-template, Pro: Read one Elementor library template: its type, display conditions and element countimport-template, Pro: Create an elementor_library template from an export-page or export-template envelope, also across sites. Element ids are regenerated; the envelope’s page_settings and display conditions apply when present. Not snapshotted (creates only); remove with delete-postlist-code-snippets, Pro: List the Elementor Custom Code snippets stored on this site (elementor_snippet posts) with their location, priority and codelist-dynamic-tags, Pro: List registered Elementor dynamic tags (name, title, group), optionally by group. Most come from Elementor Pro, so the list is short or empty without itlist-global-classes, Pro: List the Elementor v4 global CSS classes of the active kit in stored order (empty when the feature has not been used), with the state_hash the global class write tools require as expected_hashlist-theme-templates, Pro: List Elementor theme-builder templates (header, footer, single, archive, …), optionally filtered to one template_type, each with its display conditionsmove-element, Pro: Reparent an element by id: remove it and append it as a child of a new parent in the page’s _elementor_data. Refuses moves into itself or its descendants. Undo: rollback-operation (post snapshot)remove-element, Pro: Remove an element (and its children) from a page’s _elementor_data by id. Undo: rollback-operation (_elementor_data is ordinary postmeta the post snapshot captures)replace-system-colors, Pro: Atomically replace all four Elementor system color slots (primary, secondary, text, accent) on the active kit: each exactly once with a valid hex color, or nothing is written. No “title” keeps the current one. Needs expected_hash from get-global-settings. Undo: rollback-operationreplace-system-typography, Pro: Atomically replace all four Elementor system typography slots (primary, secondary, text, accent) on the active kit: each exactly once, or nothing is written. Each entry needs at least one typography_* field; unknown keys are refused; a font enables custom typography; no “title” keeps the current one. Needs expected_hash from get-global-settings. Undo: rollback-operationresolve-theme-template, Pro: Which Elementor theme-builder template wins for a location (header, footer, single, archive, …): every candidate with its conditions, specificity and matching excludes, plus the winner. post_type/post_id resolve against a real target, else only specificity countssave-as-template, Pro: Save a page’s Elementor content as a reusable elementor_library template of template_type (page, section, container, header, footer, single, archive, popup, …; default page). Not snapshotted (creates only); remove with delete-postset-dynamic-tag, Pro: Bind an Elementor dynamic tag to an element setting, written into settings[dynamic][setting_key] in Elementor’s [elementor-tag …] format; other bindings are kept. Needs expected_hash from get-elementor-data. Undo: rollback-operationset-popup-settings, Pro: Set an Elementor popup’s trigger/display settings (open/close triggers, timing, advanced rules), merged into the popup’s _elementor_page_settings. Snapshot-first; undo: rollback-operationset-template-conditions, Pro: Set where an Elementor theme template renders: conditions as part arrays ([“include”,“singular”,“post”]) or slash strings (“include/general”), through Elementor Pro’s conditions manager when present, else the same _elementor_conditions meta. Snapshot-first; undo: rollback-operationupdate-element, Pro: Update an Elementor element’s settings by id, merging the given settings into its existing settings. Writes the page’s _elementor_data, snapshot-first; undo: rollback-operationupdate-global-colors, Pro: Update the active Elementor kit’s global colors: system_colors entries patch the four system tokens by _id (color/title); custom_colors entries update one by _id or append. Colors must be hex. Needs expected_hash from get-global-settings. Undo: rollback-operationupdate-global-typography, Pro: Update the active Elementor kit’s global typography: system_typography entries patch the four system tokens by _id; custom_typography entries update one by id or append. typography* fields merge in; setting a font enables custom typography so the token renders. Needs expected_hash from get-global-settings. Undo: rollback-operationupdate-widget, Pro: Patch a cataloged widget’s settings by element id from typed params (add-widget’s schema; see get-widget-schema), validated and merged. Non-cataloged widgets are refused toward update-element. Needs expected_hash from get-elementor-data. Undo: rollback-operation
Elementor structural suite (8 tools, 8 Pro)
add-container, Pro: Create an Elementor layout element (container by default, or section/column) at top level or under parent_id, optional position. Columns need a parent; widgets are never parents. Needs expected_hash from get-elementor-data; stale reads refused. Undo: rollback-operationbatch-update, Pro: Apply N Elementor element settings updates atomically under ONE snapshot: every {element_id, settings} is validated first, one unknown id refuses the batch, and any failure rolls it all back. Needs expected_hash from get-elementor-data. One rollback-operation undoes itduplicate-element, Pro: Deep-copy an Elementor element and its subtree with fresh ids, inserted right after the original. New ids use Elementor’s 7-char hex format and are unique on the page. Needs expected_hash from get-elementor-data. Undo: rollback-operationfind-element, Pro: Search a page’s Elementor tree by el_type, widget_type, setting_key + setting_value and/or css_class (AND-combined, at least one). Each match reports element_id, types, navigator label and ancestor path; returns the current data_hash to chain a mutationreorder-elements, Pro: Reorder the children of one Elementor parent (or the top level without parent_id) to an explicit id order, which must be an exact permutation of the current children. Needs expected_hash from get-elementor-data. Undo: rollback-operationset-element-label, Pro: Set an Elementor element’s navigator label (stored as the _title setting); an empty label clears the custom name. All other settings survive untouched. Needs expected_hash from get-elementor-data. Undo: rollback-operationupdate-container, Pro: Merge settings into an Elementor container, section or column by id: given keys are set, others survive. Widgets are refused (use update-element). Needs expected_hash from get-elementor-data. Undo: rollback-operationupdate-page-settings, Pro: Merge settings into a page’s Elementor page settings (_elementor_page_settings): given keys are set, others survive. Post field keys (post_title, post_status, template, …) are refused, use the post tools. Needs expected_hash = settings_hash from get-elementor-data. Undo: rollback-operation
Elementor v4 atomic elements (4 tools, 4 Pro)
add-atomic-widget, Pro: Add an Elementor 4.0+ atomic widget (e-* widgetType, e.g. e-heading, e-paragraph, e-button, e-image) to a page. Friendly params (title, content, text, image_url, alt, link) become typed $$type props for known types; any type also takes raw $$type-wrapped settings.add-div-block, Pro: Add an Elementor 4.0+ atomic div-block (e-div-block) to a page under parent_id (or top level), optional position.add-flexbox, Pro: Add an Elementor 4.0+ atomic flexbox (e-flexbox) to a page under parent_id (or top level), optional position.update-atomic-widget, Pro: Update an Elementor 4.0+ atomic widget’s settings by element id. Friendly params map to typed $$type props for known types (only those passed change); raw $$type-wrapped settings also work.
Elementor global classes (4 tools, 4 Pro)
create-global-class, Pro: Create an Elementor v4 global class (Class Manager) with a label and styles; returns its g- id. Pass friendly “styles” and/or raw $$type “props”, optional breakpoint/state; validated against Elementor’s schema, so a property it would drop is refused. Needs expected_hash from list-global-classes. Undo: rollback-operationdelete-global-class, Pro: Delete an Elementor v4 global class by g- id. Without confirm:true it is a dry run listing every post using the class; with it, the class set is snapshotted, then the class deleted (rollback-operation restores it). Needs expected_hash from list-global-classesreorder-global-classes, Pro: Set the order of Elementor v4 global classes, which is their CSS source order and decides ties at equal specificity. Pass order: [g-id, …]; omitted classes follow in current order and unknown ids are refused. Needs expected_hash from list-global-classes. Undoableupdate-global-class, Pro: Update an Elementor v4 global class by g- id: rename it and/or merge styles into one breakpoint + state variant (replace_variant:true replaces it), so other responsive or hover rules survive. Needs expected_hash from list-global-classes. Undo: rollback-operation
Elementor global variables (4 tools, 4 Pro)
create-global-variable, Pro: Create an Elementor v4 global variable; returns its e-gv- id. label is the CSS variable name (letters, digits, - _). value: hex/rgb()/hsl() color, font family, size like 16px, or any CSS for custom-size (sizes need Elementor Pro). Needs expected_hash from list-global-variables. Undoabledelete-global-variable, Pro: Delete an Elementor v4 global variable by e-gv- id. Without confirm:true it is a dry run listing the posts and classes using it. Needs expected_hash from list-global-variables. Undoablelist-global-variables, Pro: List Elementor v4 global variables (color, font, size design tokens) with the state_hash the write tools need as expected_hashupdate-global-variable, Pro: Update an Elementor v4 global variable by e-gv- id: label, value, or size/custom-size switch (no other type change). Needs expected_hash from list-global-variables. Undoable
Brand kits (4 tools, 4 Pro)
apply-brand-kit, Pro: Apply a brand kit to the active Elementor kit (system colors, swatches, the four system typography tokens, logo) as ONE snapshotted operation. Without confirm:true it only returns the per-token diff and settings_hash; with it, expected_hash must match. Any invalid entry refuses the whole kit. Undo: rollback-brand-kit or rollback-operationget-brand-kit, Pro: Return one brand kit in the shape apply-brand-kit writes: system slots as hex, named swatches with id, typography mapped to Elementor typography* fields. Entries failing validation are listed in “invalid” and make the kit unappliablelist-brand-kits, Pro: List brand kits (bundled presets plus any from the wpmcp_brand_kits option or filter): slug, category, source, the four system colors, font families, logo flag. Filter by category, source (bundled/site) or searchrollback-brand-kit, Pro: Undo a brand-kit apply by restoring its single snapshot (palette, swatches, typography, logo). Defaults to the most recent apply not yet rolled back; pass operation_id to target a specific apply
Custom widget builder (9 tools, 9 Pro)
compile-custom-widget, Pro: Compile a published custom-widget spec into a native Elementor widget; the plugin, never the agent, writes and lints the PHP. Off unless wpmcp_enable_widget_compiler is on; needs edit_files, honors DISALLOW_FILE_EDIT. set-widget-status disables itcreate-custom-widget, Pro: Create a custom Elementor widget from a data spec (title, controls, template with {{name}} placeholders), stored as a wpmcp_widget post. Without unfiltered_html the template is wp_kses_post-filtered (template_filtered: true)delete-custom-widget, Pro: Move a custom widget to the trash (reversible via restore-post)get-custom-widget, Pro: Read a custom widget’s stored spec by idlist-control-types, Pro: List the control types a custom-widget spec may use and their Elementor controlslist-custom-widgets, Pro: List this site’s custom widgets (id, name, title, active/inactive)set-widget-status, Pro: Enable (publish) or disable (draft) a custom widget by idupdate-custom-widget, Pro: Replace a custom widget’s spec by id (re-validated; same wp_kses_post gate as create)validate-widget-spec, Pro: Validate a custom-widget spec without storing it
Page builders: Bricks, Divi, WPBakery, Beaver Builder, Breakdance, Oxygen, Avada, Thrive (3 tools, 3 Pro)
detect-builder, Pro: Post builder: elementor, bricks, divi, wpbakery, avada, beaver-builder, breakdance, oxygen, oxygen-classic, thrive, gutenberg, classic. Read-onlyget-builder-content, Pro: Bricks elements; Divi/WPBakery/Avada shortcodes, Thrive HTML, oxygen-classic JSON (last four with paths); Beaver Builder/Breakdance/Oxygen nodes. Or scope design_system|templates|catalog (element: its controls) for builder bricks|breakdance|oxygen. Read-onlyupdate-builder-content, Pro: Bricks JSON; Divi/WPBakery/Avada shortcodes, Thrive HTML; oxygen-classic/Beaver Builder/Breakdance/Oxygen JSON tree. All but Bricks/Divi: operation update (path, attrs, text), add (to, index, element), remove (path), move (path, to, index); to “” = top. scope design_system (bricks|breakdance): add/update/remove at classes|variables|palettes/[/ ]; expected_hash: read’s hashes. - . Undo: rollback-operation
Theme structure (sidebars, shortcodes) (8 tools)
create-sidebar-widget: Add a classic widget (registered id_base, incl. block) to a sidebar at a 0-based position, sanitized by its update(). Undoabledelete-sidebar-widget: Delete a classic widget instance. Undoablelist-shortcodes: List registered shortcode tags ($shortcode_tags): tag name and a short description of its callback where resolvable. Optional search (substring of the tag name) narrows the resultlist-sidebar-widgets: List the widgets assigned to a single sidebar (by sidebar_id): widget id and display name, from wp_get_sidebars_widgets() resolved against the registered widgetslist-sidebars: List the sidebars/widget areas registered via register_sidebar(): id, name, descriptionmove-sidebar-widget: Move a classic widget to a sidebar or wp_inactive_widgets at a 0-based position. Undoablerender-shortcode: Render a shortcode string (e.g. “[gallery ids="1,2"]”) via do_shortcode() and return the HTML. Only invokes registered shortcode tags; input without an opening “[” is refusedupdate-sidebar-widget: Merge settings into a classic widget (id like text-2) via its update(). Undoable
Content export & import (3 tools)
export-content: WXR export via core export_wp(), narrowed by content, author, start_date, end_date, status, to a protected uploads dir; returns path, size, count. Once per PHP process (core limit). mirror:true instead writes builder pages as stable JSON for git (post_id, or all 50 per page)import-content: Import a WXR file as new posts (title, content, status, post_type, postmeta). Off by default (wpmcp_enable_import filter), needs confirm:true, not snapshotted (recoverable:false); returns created_post_ids for delete-post. mirror:true + post_id restores that page from its export-content mirror (undoable)list-exports: List the WXR export files previously generated by export-content: file name, size in bytes and created timestamp for each
Async backups (7 tools)
cancel-backup-job: Cancel a queued backup job: unschedule its WP-Cron event and mark it canceled. Errors if the job is unknown or no longer queued (running or terminal)delete-backup-archive: Delete a site-backup archive by job id or path and report bytes freed. The job record stays, flagged deleted, so history never points at a missing file. Paths outside the site-backup directory are refusedget-backup-manifest: Read a completed site-backup archive’s manifest by job id or path: origin site_url/home_url, table prefix, multisite, WordPress/PHP/plugin versions, scope, per-table row counts, BLOB tables and file count. Read-only; paths outside the site-backup dir are refusedget-backup-status: Return a backup job’s current record (status: queued/running/completed/failed/canceled, result artifact reference or error, timestamps) by job idlist-backup-jobs: List backup jobs, newest first, optionally by status (queued/running/completed/failed/canceled), plus schedules (next run, overdue, last run)restore-site-backup: Restore this site in place from a site-backup archive (job_id, or a path in the site-backup dir). dry_run (default true) reports format_version, scope (all/database), prefix, multisite, WP downgrade, BLOB tables and a full db.sql parse (truncated dumps refused). dry_run=false takes a database safety archive first (job id returned; no restore if it fails), holds maintenance mode, imports each statement and rolls back on failure. preserve_session (default true) keeps the caller signed in; include_files (default false, scope all) swaps in staged wp-contenttrigger-backup: Queue a WP-Cron backup job; returns its job id. type=full: portable site archive (zip: full SQL dump, wp-content, origin manifest) to restore or migrate; database/files/uploads narrow it; content: WXR export. every=daily [HH:MM], weekly [mon-sun] [HH:MM] (site time) or off schedules that type instead; each run prunes its archives past keep (default 7), never manual ones or after a failed run
Migration: find & replace, URL rewrite, site push (4 tools)
find-replace-content: Serialization-safe find and replace in post content, titles, excerpts or meta. dry_run (default) previews; apply returns a rollback-session id; over 10 posts needs confirm:truepush-site-archive: Push a site-backup archive (job_id or path; scope all or database) to another wpmcp site at target_url as its admin (target_user + target_app_password, or target_token). dry_run (default) only checks the target; dry_run:false + confirm:true uploads resumable chunks for max_seconds (call again to continue); apply:true has the target restore it (safety archive first) and rewrite URLs. Needs the outgoing-migration opt-in here, incoming therereceive-site-archive: Target side of push-site-archive. action start (sha256, bytes, manifest; checked before upload, resumes), chunk (upload_id, offset, base64 data), status, apply (verify, restore with a safety archive, rewrite URLs; dry_run default, confirm:true applies). Needs the incoming-migration opt-inrewrite-site-urls: Rewrite one site URL to another across the database (options, postmeta, posts, termmeta, usermeta, comments), serialization-aware for plain, JSON-escaped, percent-encoded and scheme-relative forms; object values are refused and reported. dry_run (default) reports per-table counts; dry_run:false + confirm:true takes a database safety archive first or refuses, returning its job_id for restore-site-backup. Skips wpmcp_db_protected_tables (usermeta by default); never rewrites GUIDs
Local to live sync (change sets) (3 tools)
apply-change-set: Apply a change set (change_set from get-change-set raw=true, or path) here; dry_run defaults to true. Only selected objects are written, snapshot-first; media, terms and templates are only added; objects changed here since the base are refused unless keyed in force; deletions never apply. rollback-session undoes itbuild-change-set: Build a local-live sync change set (objects, media bytes, terms, templates, global classes, base revisions) from a ledger marker (session_id, operation_id or since_id) and/or object refs (post:ID, option:theme_mods_X, term:TAX:SLUG) as a JSON artifact in the site-backup dir. dry_run only lists itget-change-set: Inspect a change-set artifact before it is applied: origin, objects, dependencies, exclusions, truncation. include_objects=true adds full data; raw=true returns the artifact to pass to apply-change-set on the target. Read-only; site-backup dir only
Database (6 tools)
delete-rows: Delete rows matching a mandatory equality WHERE. Needs confirm:true and the wpmcp_enable_db_writes filter; refuses protected tables. Undo: rollback-operation (rows reinserted with their ids) if the table has a primary key and the WHERE fits the before-image cap, else recoverable:false with the before-image in the write audit logdescribe-table: Return the columns, types and keys of a database tableinsert-row: Insert a row into a table via $wpdb->insert() (parameterized). Refuses protected tables. Disabled by default (wpmcp_enable_db_writes filter)list-tables: List database tables with estimated row counts and sizesquery: Run a read-only SQL query (SELECT/SHOW/DESCRIBE/EXPLAIN/WITH). Writes, DDL, stacked statements and file-access SQL are rejected before running. Reads of users/usermeta tables are blocked (wpmcp_db_allow_user_table_reads filter opts in, with secrets masked). Results are cappedupdate-rows: Update rows matching a mandatory equality WHERE via $wpdb->update(). Needs confirm:true and the wpmcp_enable_db_writes filter; refuses protected tables. Undo: rollback-operation if the table has a primary key and the WHERE fits the before-image cap, else recoverable:false with the before-image in the write audit log
Filesystem (6 tools)
delete-file: Delete a file in the WordPress install. Needs confirm:true. Backs up the file (restore recovers it). Refuses wp-config.php/.htaccess. Off by default (wpmcp_enable_fs_writes filter); needs edit_files, honors DISALLOW_FILE_EDITedit-file: Replace an exact string in a file (must match once unless replace_all). Backs up the original (restore recovers it). Refuses wp-config.php/.htaccess. Off by default (wpmcp_enable_fs_writes filter); needs edit_files, honors DISALLOW_FILE_EDIT. PHP is checked and reverted as in write-filelist-directory: List entries (files/dirs with size and mtime) of a directory inside the WordPress install. Optional bounded recursive listingread-file: Read a file inside the WordPress install (core, plugins, themes, uploads); the path cannot leave itsearch-files: Search file contents for a substring across a directory tree inside the WordPress install. Filterable by extension; results are cappedwrite-file: Create or overwrite a file in the WordPress install. Backs up an existing file (restore recovers it). Refuses wp-config.php/.htaccess. Off by default (wpmcp_enable_fs_writes filter); needs edit_files, honors DISALLOW_FILE_EDIT. PHP must parse; a fatal on the front end or admin after saving reverts it; if that check cannot run, refused unless unchecked:true
Scanners & cache (4 tools)
analyze-performance: Scan server config, WordPress internals (database size, autoloaded options, cron backlog, object cache, OPcache, plugin count) and a page (frontpage, url or post_id) for performance bottlenecks. Returns a scored report with ranked fixesclear-cache: Flush caches: object cache, all transients, OPcache when enabled and any detected page-cache plugin through its own API. Returns what each layer cleared or lacked. Idempotent; not snapshotted (a cache has no before-image)get-cache-status: Report active caching layers: the object cache backend (external or internal), OPcache and any page-cache plugin (WP Rocket, W3 Total Cache, WP Super Cache, LiteSpeed Cache, WP Fastest Cache) detected by its functions or constantsscan-security: Scan this site for malware (deep=true: whole tree), core file integrity, hardening gaps, outdated software and known vulnerabilities (vulnerabilities=true; sends slugs and versions to wpvulnerability.net). Returns a 0-100 score, A-F grade and ranked fixes
Diagnostics & transients (5 tools)
delete-transient: Delete one named transient (cache data, not snapshotted) or run cleanup: expired_transients, revisions (beyond keep newest per post, default 5), auto_drafts (7+ days old), trash (older than days, default 0), spam_comments, orphaned_meta. Dry run by default (counts, bytes, sample ids); dry_run:false+confirm applies up to 200 items/10s, returning a cursor to resume. rollback-operation undoes all but transients; attachments and parents are skippedget-debug-config: Debug constants (WP_DEBUG, WP_DEBUG_LOG, WP_DEBUG_DISPLAY, SCRIPT_DEBUG, SAVEQUERIES) and, when logging is on, the debug.log path. No secretsget-debug-log: Bounded tail (max 200 lines / 64KB) of the debug log, by default WP_CONTENT_DIR/debug.log or the WP_DEBUG_LOG path. A path argument is confined to WP_CONTENT_DIRget-site-health: Run Site Health tests, plugin-added ones included, as plain text. Async tests past timeout seconds (default 10, max 30) report not completed. cached: last full run. mail_test: how mail is sent (no secrets); your or admin email + confirm sends a test (manage_options, rate limited)list-transients: List transients (name, expiry) with an optional search substring; limit default 50, max 500
Advanced Custom Fields (3 tools)
get-fields: Read a post’s ACF field values, keyed by field name, via get_fields()list-field-groups: List registered ACF (Advanced Custom Fields) field groups: key, title, flattened location rules and whether each is activeupdate-fields: Set one or more ACF field values on a post via update_field(). Snapshotted as a post; rollback-operation restores the prior values exactly. Disabled by default (site must opt in via the wpmcp_enable_acf_write filter)
Integrations (read/write dispatcher pairs) (26 tools)
acf-read: Read op on Advanced Custom Fields (field groups, post types, taxonomies, options and field values): operation + its args (list-operations lists each op’s schema)acf-write: Write op on Advanced Custom Fields (field groups, post types, taxonomies, options and field values): operation + args per its schema (list-operations on the read half). Snapshot-first if possible (undo: rollback-operation); destructive ops need confirm:truecontactform7-read: Read op on Contact Form 7 (forms, markup, mail templates, Flamingo entries): operation + its args (list-operations lists each op’s schema)contactform7-write: Write op on Contact Form 7 (forms, markup, mail templates, Flamingo entries): operation + args per its schema (list-operations on the read half). Snapshot-first if possible (undo: rollback-operation); destructive ops need confirm:trueforminator-read: Read op on Forminator (forms, their field definitions, and submissions): operation + its args (list-operations lists each op’s schema)forminator-write: Write op on Forminator (forms, their field definitions, and submissions): operation + args per its schema (list-operations on the read half). Snapshot-first if possible (undo: rollback-operation); destructive ops need confirm:truegive-read: Read op on GiveWP (donation forms, pricing, goals, and totals): operation + its args (list-operations lists each op’s schema)give-write: Write op on GiveWP (donation forms, pricing, goals, and totals): operation + args per its schema (list-operations on the read half). Snapshot-first if possible (undo: rollback-operation); destructive ops need confirm:truegravitytables-read: Read op on Gravity Tables (data tables built from Gravity Forms entries): operation + its args (list-operations lists each op’s schema)gravitytables-write: Write op on Gravity Tables (data tables built from Gravity Forms entries): operation + args per its schema (list-operations on the read half). Snapshot-first if possible (undo: rollback-operation); destructive ops need confirm:truemec-read: Read op on Modern Events Calendar (events and their schedules): operation + its args (list-operations lists each op’s schema)mec-write: Write op on Modern Events Calendar (events and their schedules): operation + args per its schema (list-operations on the read half). Snapshot-first if possible (undo: rollback-operation); destructive ops need confirm:truemetabox-read: Read op on Meta Box (registered meta boxes and per-post custom field values): operation + its args (list-operations lists each op’s schema)metabox-write: Write op on Meta Box (registered meta boxes and per-post custom field values): operation + args per its schema (list-operations on the read half). Snapshot-first if possible (undo: rollback-operation); destructive ops need confirm:truemetform-read: Read op on MetForm (forms, their Elementor field definitions, and entries): operation + its args (list-operations lists each op’s schema)metform-write: Write op on MetForm (forms, their Elementor field definitions, and entries): operation + args per its schema (list-operations on the read half). Snapshot-first if possible (undo: rollback-operation); destructive ops need confirm:trueplugin-data-read: Read op on the plugin-data integration: operation + its args (list-operations lists each op’s schema)plugin-data-write: Write op on the plugin-data integration: operation + args per its schema (list-operations on the read half). Snapshot-first if possible (undo: rollback-operation); destructive ops need confirm:truepmpro-read: Read op on Paid Memberships Pro (membership levels, pricing, and member counts): operation + its args (list-operations lists each op’s schema)pmpro-write: Write op on Paid Memberships Pro (membership levels, pricing, and member counts): operation + args per its schema (list-operations on the read half). Snapshot-first if possible (undo: rollback-operation); destructive ops need confirm:truesureforms-read: Read op on SureForms (forms, their block field definitions, and entries): operation + its args (list-operations lists each op’s schema)sureforms-write: Write op on SureForms (forms, their block field definitions, and entries): operation + args per its schema (list-operations on the read half). Snapshot-first if possible (undo: rollback-operation); destructive ops need confirm:truetec-read: Read op on The Events Calendar (events and their schedules): operation + its args (list-operations lists each op’s schema)tec-write: Write op on The Events Calendar (events and their schedules): operation + args per its schema (list-operations on the read half). Snapshot-first if possible (undo: rollback-operation); destructive ops need confirm:truetheme-read: Read op on the active theme (context, supports, theme mods), Redirection, and backup, security, analytics and cache status: operation + its args (list-operations lists each op’s schema)theme-write: Write op on the active theme (context, supports, theme mods), Redirection, and backup, security, analytics and cache status: operation + args per its schema (list-operations on the read half). Snapshot-first if possible (undo: rollback-operation); destructive ops need confirm:true
Forms adapter pack (10 tools, 10 Pro)
fluentforms-read, Pro: Read op on Fluent Forms (forms, fields, notifications, entries): operation + its args (list-operations lists each op’s schema)fluentforms-write, Pro: Write op on Fluent Forms (forms, fields, notifications, entries): operation + args per its schema (list-operations on the read half). Snapshot-first if possible (undo: rollback-operation); destructive ops need confirm:trueformidable-read, Pro: Read op on Formidable Forms (forms, fields, notifications, and entries): operation + its args (list-operations lists each op’s schema)formidable-write, Pro: Write op on Formidable Forms (forms, fields, notifications, and entries): operation + args per its schema (list-operations on the read half). Snapshot-first if possible (undo: rollback-operation); destructive ops need confirm:truegravityforms-read, Pro: Read op on Gravity Forms (forms, fields, notifications, entries, entry notes): operation + its args (list-operations lists each op’s schema)gravityforms-write, Pro: Write op on Gravity Forms (forms, fields, notifications, entries, entry notes): operation + args per its schema (list-operations on the read half). Snapshot-first if possible (undo: rollback-operation); destructive ops need confirm:trueninjaforms-read, Pro: Read op on Ninja Forms (forms, fields, notifications, submissions): operation + its args (list-operations lists each op’s schema)ninjaforms-write, Pro: Write op on Ninja Forms (forms, fields, notifications, submissions): operation + args per its schema (list-operations on the read half). Snapshot-first if possible (undo: rollback-operation); destructive ops need confirm:truewpforms-read, Pro: Read op on WPForms (forms, fields, notifications; entries with entry storage): operation + its args (list-operations lists each op’s schema)wpforms-write, Pro: Write op on WPForms (forms, fields, notifications; entries with entry storage): operation + args per its schema (list-operations on the read half). Snapshot-first if possible (undo: rollback-operation); destructive ops need confirm:true
Internationalization (Polylang) (4 tools)
get-post-translations: Read a post’s translations (the translated post id and title, keyed by language code) via the active multilingual plugin (Polylang or WPML)link-post-translations: Link posts as translations of one another from {language, post_id} pairs via Polylang or WPML. Only the primary (first) post is snapshotted, so rollback restores that post, not the otherslist-languages: List the site’s languages (code, name, which is default) via the active multilingual plugin (Polylang or WPML)set-post-language: Assign a post to a language (by code) via the active multilingual plugin (Polylang or WPML). Snapshotted as a post (a Polylang language is a term); rollback-operation restores the prior language assignment exactly
Multisite (4 tools)
get-network-info, requires an optional companion plugin or multisite: Report this network’s id, name, domain, total site count, and main site id, via get_network()/get_main_site_id()get-site-details, requires an optional companion plugin or multisite: Report a single network site’s details (blog_id, url, name, last_updated) by blog_id, via get_site()/get_blog_details(). Returns an error for an unrecognized blog_idis-multisite: Whether this install is a multisite network. Always registered, even on single-site, so network status can be checked before the other multisite toolslist-network-sites, requires an optional companion plugin or multisite: List sites on the network (blog_id, url, name, last_updated) via get_sites(), with optional limit (default 50) and offset for pagination. limit is capped at 500
Analytics & Search Console (5 tools)
get-analytics-connection-status: Whether an analytics provider (Google Site Kit or configured credentials) is active and appears connected. Always registered, so it can be checked before the other analytics toolsget-analytics-summary: Read-only sessions/users/pageviews summary over a date range (Y-m-d; default the 28 days ending yesterday) from the connected analytics provider. Errors when no provider is connectedget-search-console-queries: Read-only list of top search queries by clicks over a date range (Y-m-d; default the 28 days ending yesterday) from the connected Search Console provider; limit default 10, max 100. Errors when no provider is connectedget-search-console-summary: Read-only clicks/impressions/ctr/position summary over a date range (Y-m-d; default the 28 days ending yesterday) from the connected Search Console provider. Errors when no provider is connectedget-top-pages: Read-only list of top pages by pageviews over a date range (Y-m-d; default the 28 days ending yesterday) from the connected analytics provider; limit default 10, max 100. Errors when no provider is connected
Cron (4 tools)
list-cron-events: List the scheduled WP-Cron events (hook, next-run timestamp, recurrence/schedule, interval in seconds, callback args) from the cron array, plus the available schedules from wp_get_schedules(). Optional hook filterrun-event: Fire a scheduled cron hook now via do_action(), for debugging. Off until the wpmcp_enable_run_cron_event filter opts in; fires only hooks present in the cron array, always with their stored args. Not snapshotted: firing a hook is irreversibleschedule-event: Schedule a recurring (recurrence checked against wp_get_schedules()) or single event. Refuses core-critical hooks (wp_version_check, wp_update_plugins/themes, wp_scheduled_delete, delete_expired_transients, wp_privacy_delete_old_export_files). Snapshots the cron option; rollback-operation restores itunschedule-event: Unschedule one occurrence (wp_unschedule_event, given timestamp and matching args) or every event for a hook (wp_clear_scheduled_hook). Core hooks included, made safe by snapshotting the cron option: rollback-operation restores it
Maintenance mode (3 tools)
disable-maintenance: Turn maintenance mode off: sets enabled=false on the wpmcp_maintenance option (message and retry_after are preserved for a later re-enable). Snapshotted; rollback-operation restores the prior stateenable-maintenance: Turn maintenance mode on (wpmcp_maintenance option: enabled, message, retry_after seconds). Logged-out visitors and users without manage_options get a 503 with the message until disabled. Snapshotted; rollback-operation restores the prior stateget-maintenance-status: Whether maintenance mode is on and, if so, its message and Retry-After seconds
Site context (3 tools)
get-page-snapshot: One-call page digest from stored post_content: structure counts, outline, media and link inventory, builder detection, SEO-lite signals (content_coverage flags builder page gaps). Heavy sections (global_tokens, responsive_overrides) opt-in via sections. Size-cappedget-rendered-html: Visitor-view HTML of a site page (post_id or url/path), chunkedget-site-context: Orientation payload: site name, URL, tagline, WordPress and PHP versions, theme, active plugins, public post types with counts, taxonomies, user count, locale, timezone, multisite and active integrations. No admin email
REST passthrough (2 tools)
call-rest: Run an internal REST request on any local route; returns status and body. The route’s permission_callback runs as the current user, so access cannot widen. GET/HEAD always run; writes need the wpmcp_enable_rest_writes filter (default off) and confirm:true, and are not snapshotted (recoverable:false)list-rest-routes: List routes on this site’s REST server (core and plugin namespaces): path, methods and a short args summary. Optional namespace and search filter by substring; limit caps rows (default 50, max 200). Read-only: never executes a route
Onboarding & connection info (2 tools)
get-connection-info: How to connect an MCP client here: the MCP endpoint URL and ready-to-paste snippets for Claude Code, Cursor and Claude Desktop, each using an Application Password placeholder. Never returns a real credential. Read-onlylist-tool-catalog: List every wpmcp ability here grouped by domain, with tier (free/pro), operation, required capability and read-only/destructive hints, plus per-domain counts. Optional domain and tier filters. Read-only
Tool dispatch (compact mode) (3 tools)
call-tool: Invoke any wpmcp tool by name with an arguments object (reaches tools compact mode hides). The target’s own checks (capability, governance, identity scope, license, rate limit, input validation, snapshot/rollback) apply as if called directly, never widening access. Refuses non-wpmcp tools and the meta-toolsget-tool-schema: Read one wpmcp tool’s full contract by name: exact input schema, complete description, MCP annotations and domain/operation/tier. Read-only; list-tools finds nameslist-tools: List every tool this install registers: name, summary, domain, operation and tier, by name. Optional domain filter; full:true adds full descriptions and MCP annotations; schemas are behind get-tool-schema. Read-only. In compact mode, the discovery entry point for unlisted tools
Governance & scoped identities (6 tools)
create-identity: Create or overwrite (by name) a scoped identity that, once active (wpmcp_current_identity filter), narrows abilities beyond capability and Governance. Optional domains/operations/abilities allowlists, mode (allow default, or deny), exposure (full/compact, overrides site-wide mode), allowed_ips (IPs/CIDRs; other clients refused)delete-identity: Delete a scoped identity by name. Returns an error if no identity with that name existsget-governance-settings: Return the stored governance toggle maps (ability, domain, operation) and site_wide mode: explicit enable/disable decisions layered on top of the wpmcp_{ability,domain,operation}_enabled filterslist-governance-audit-log: List governance-decision audit log entries (ability, active identity or “none”, allowed/denied, timestamp, source: mcp/rest/server/cli/php), newest first. Optional limit (default 20) and source filterlist-identities: List every registered scoped identityupdate-governance-settings: Batch-update stored governance toggles by ability, domain and operation, e.g. {ability: {“wpmcp/delete-post”: false}, domain: {“database”: false}}. Invalid entries are skipped and reported; only empty input throws. site_wide audits ability calls outside MCP; enforce also refuses abilities toggled off by name
Project memory (3 tools, 3 Pro)
memory-propose, Pro: Propose one durable memory entry, stored PENDING and inert (not injected into sessions; severity=block not enforced) until an admin publishes it in wp-admin. severity=block needs at least one target (tool:, post_id: , post_type: ); once published, matching calls are refused (enforced, not advisory) memory-recall, Pro: Read this site’s APPROVED project memory: published facts, conventions, guardrails, session summaries and enforced block rules. Pending proposals are never returned (only their count), so unapproved suggestions never read back as policymemory-save-summary, Pro: Record what a session changed as a pending session-summary entry. Facts come from that session’s snapshot rows, not the supplied prose or any LLM, so it cannot over- or under-claim. Optional takeaways are filed as separate pending proposals
Skills (2 tools)
get-skill: Load one skill’s full instructions by slug (from list-skills), returned exactly as written. Unknown slugs return a structured error listing the installed slugslist-skills: List installed agent skills (versioned markdown playbooks): slug, name, description, version, tags. Bodies via get-skill. Skills whose required tools are missing are hidden unless include_unavailable is set
Ability bridge (other plugins’ abilities) (3 tools)
execute-site-ability: Invoke one third-party ability by name with an arguments object. Its own permission callback always runs, plus wpmcp governance, identity scope and rate limiting. Results are reversible:false (bridged writes are outside wpmcp rollback). Refuses wpmcp’s own abilities; needs the site bridge opt-in (default off)get-site-ability: Read one third-party ability’s full contract by name: description, input and output schemas, meta where provided, and owning plugin. Refuses wpmcp’s own abilities (use get-tool-schema). Read-only; list-site-abilities finds nameslist-site-abilities: Abilities OTHER plugins register via the Abilities API: name, summary, owning plugin, whether an input schema exists and reversible:false (bridged results are outside wpmcp rollback). Optional plugin filter. Needs the ability bridge opt-in (default off)
Gateway credentials (3 tools)
gateway-provision: Provision or rotate the site gateway credential. Returns client_id, client_secret and refresh_token once; the previous credential dies immediately. Carries the calling user’s capabilities. Requires confirm: truegateway-revoke: Revoke the site gateway credential and every token bound to it. Local, idempotent. Requires confirm: truegateway-status: Whether the site gateway credential exists, its client_id and whether OAuth is enabled. Never returns secrets
WP MCP Cloud: sync & marketplace (12 tools, 12 Pro)
cloud-apply-settings, Pro: Apply a posture: a cloud-sync-settings map, or (settings omitted) the last pushed one. Re-filtered to the allowlist; toggles and identities merge, scope fields only; never changes the MCP exposure switch or disables rollback-operation. Paid. Each write snapshotted; applied[i] pairs with operation_ids[i]; matching options listed as unchangedcloud-connect, Pro: Connect this site to WP MCP Cloud: store the cloud url + api key and verify them by fetching the account, which is returned. gateway_consent (default false) permits a gateway credential upload; false withdraws it and kills any the cloud holdscloud-gateway-provision, Pro: Mint the gateway credential bound to a scoped identity (MCP connection, that allowlist only) and upload it. Needs consent=true; replace=true kills a live one. Upload needs cloud-connect gateway_consent. Secrets shown ONCE. Revoke: gateway-revokecloud-gateway-status, Pro: Gateway credential’s bound identity, upload and consent state. No secretscloud-list-assets, Pro: List the assets (widget/block specs) in this site’s WP MCP Cloud accountcloud-marketplace-browse, Pro: Browse WP MCP Cloud marketplace widget and block specs, optionally by type and searchcloud-marketplace-install, Pro: Install a WP MCP Cloud marketplace listing by slug: validated like validate-widget-spec / validate-block-spec, template run through wp_kses_post, lands INACTIVE until set-widget-status / set-block-status. Refuses a name colliding with a local speccloud-pull-assets, Pro: Pull this site’s WP MCP Cloud builder assets and recreate them as local custom widget/block specs (each validated first; refusals listed under skipped with a reason)cloud-push-assets, Pro: Push this site’s custom widget and block specs up to WP MCP Cloud (backup + reuse across sites). Optional type filter (widget|block)cloud-push-settings, Pro: Push the cloud-sync-settings posture plus identity scopes (no secrets) to WP MCP Cloud for cloud-apply-settings elsewhere. Paid. Changes nothing herecloud-status, Pro: Whether this site is connected to WP MCP Cloud, and wherecloud-sync-settings, Pro: Preview what would sync to WP MCP Cloud: governance toggles, MCP exposure switch, tool-exposure mode, skills switch. Never secrets or code-level gates (db writes, php exec, cli allowlist)
PHP snippet validation (1 tool)
validate-php-snippet: Statically check a PHP snippet without running it: syntax validity (error message and line) and severity-tagged findings (eval, exec, shell_exec, backticks, obfuscation decoders, request-driven input, outbound HTTP)
PHP snippet store (6 tools)
create-php-snippet: Store a named PHP snippet, inactive (not Elementor custom code: see create-code-snippet). Never executed; syntax errors or critical static findings refuse it (advisory, not a security boundary). Activation is separate and gated. Snapshot-first, reversible per snippetdeactivate-php-snippet: Deactivate a stored PHP snippet by id (reverse of activate-php-snippet). Not gated on the PHP execution opt-in, so an active snippet can always be revoked. Snapshot-first; never executes anythingdelete-php-snippet: Delete a stored PHP snippet by id (not an Elementor custom-code post: see delete-code-snippet). Snapshot-first, reversible per snippet (restored inactive); never executes anythingget-php-snippet: Fetch one STORED PHP SNIPPET by id: code, status and last static-check report (advisory, not proof of safety). Not Elementor custom code (see get-code-snippet)list-php-snippets: List STORED PHP SNIPPETS as summaries (id, name, status, static-check flag, timestamps) without code. Not Elementor custom code (see list-code-snippets)update-php-snippet: Update a stored PHP snippet’s name and/or code. New code is re-checked statically (advisory, not a security boundary) and never executed; a code change resets it to inactive. Snapshot-first, reversible per snippet
Guarded WP-CLI (1 tool, 1 Pro)
run-wp-cli, Pro: Run an allowlisted wp-cli subcommand (e.g. “core version”); returns stdout, stderr, exit code. Off by default (WPMCP_ALLOW_WP_CLI or wpmcp_allow_wp_cli); refused on production without a separate override; only subcommands on the wpmcp_wp_cli_allowlist filter run; shell metacharacters are rejected first
Async WP-CLI jobs (4 tools, 4 Pro)
cancel-cli-job, Pro: Cancel a queued background CLI job: unschedule its WP-Cron event and mark it canceled so it never runs. Errors if the job is unknown or no longer queued (running or terminal)dispatch-cli-job, Pro: Queue an allowlisted wp-cli command as a background job; returns its id (poll get-cli-job). Same gates as run-wp-cli (off by default: WPMCP_ALLOW_WP_CLI or wpmcp_allow_wp_cli; production needs a separate override; allowlisted subcommands and flags; no shell metacharacters), re-checked at run time, so closing them stops queued jobs. timeout seconds (default 300, max 900). Refused while too many jobs are queued or runningget-cli-job, Pro: Return a background CLI job by id: status (queued/running/completed/failed/canceled), the dispatched command and, once run, size-capped stdout/stderr, exit code and timed-out flag, or the error that stopped itlist-cli-jobs, Pro: List background CLI jobs, newest first, with an optional status filter (queued/running/completed/failed/canceled)
Guarded PHP execution (2 tools, 2 Pro)
activate-php-snippet, Pro: Activate a STORED PHP SNIPPET by id (not Elementor custom code): flips the status flag, never executes it. Refused unless PHP execution is enabled (WPMCP_ALLOW_PHP_EXEC or wpmcp_allow_php_exec, default off) and the environment permits it (as run-php-snippet). Every attempt audited. Snapshot-first; rollback restores it inactiverun-php-snippet, Pro: Run a guarded arbitrary PHP snippet; returns its return value, output and any thrown error. REMOTE CODE EXECUTION: off by default (WPMCP_ALLOW_PHP_EXEC or wpmcp_allow_php_exec); refused on production or an unrecognized environment unless WPMCP_ALLOW_PHP_EXEC_ON_PRODUCTION is also set; the static validator rejects flagged snippets first (a speed-bump, not a security boundary). Not snapshotted; cannot be undone.
Misc (9 tools, 2 Pro)
create-comment: Comment on a post as you. status: approved (moderate_comments) or unapproved. Reversiblefind-unused-media: Attachments nothing references (featured image, site logo/icon, content, builder data, post/term meta, options) with size on disk and checks run. Pass next_cursor as cursor until done; unattached:true lists parent-0 ones apartget-preview-link: Preview URL for a draft, pending or scheduled post you can editincident-response: list-app-passwords (no secrets); revoke-app-password (uuid or all); end-sessions (user_id or all); rotate-salts (wp-config.php, backup kept; refused if unwritable or defined elsewhere); reinstall-core-files (files scan-security flags, from the checksum-verified official package, never wp-content; undo: rollback-operation). Writes need confirm:true. Cannot be undone: revoke, end-sessions, rotate-salts (logs out everyone, your cookie session too, not app passwords). Your session and app password stay unless include_current. Other users take edit_usersinstall-package-from-zip, Pro: Install or replace a plugin/theme from a Media Library ZIP. Off by default (wpmcp_enable_zip_install); needs confirm:true and its sha256. Rollbackablemanage-updates: Update WordPress core or set plugin/theme auto-updates. type=core applies the offered core update (or pending DB upgrade); needs confirm:true and a full backup (trigger-backup type=full) under 1h old; refuses if expected_version differs from the offer. A core update cannot be snapshot-rolled-back; restore that backup to revert. type=plugin|theme + item + enabled sets auto-update (undoable)optimize-media, Pro: Recompress JPEG/PNG at quality (82), cap the full size at max_edge px and write webp/avif copies of it and each size with the server image editor. No media_id: batches by cursor, or background:true queues a job under one session_id (job_id: progress; +cancel: stop). dry_run estimates. Defers to an optimizer plugin unless force. Undo: rollback-operation. Settings: wpmcp_optimize_uploads, wpmcp_serve_modern_imagesreply-to-comment: Reply to comment id; as create-commentsearch-themes: Search wordpress.org themes; filters as in search-plugins
Block Suite (2 tools, 2 Pro)
block-suites-read, Pro: Read op on block suite blocks and patterns: operation + its args (list-operations lists each op’s schema)block-suites-write, Pro: Write op on block suite blocks and patterns: operation + args per its schema (list-operations on the read half). Snapshot-first if possible (undo: rollback-operation); destructive ops need confirm:true
Bundle (2 tools)
export-bundle: Export PHP snippets, plus custom block/widget specs where present, as a checksummed JSON bundle for import-bundle; types and ids filterimport-bundle: Import an export-bundle: items are re-validated and created inactive; name clashes skip unless on_conflict=rename. Undo with rollback-session
Site Template (2 tools)
site-templates-read: List the block theme’s templates and parts (source theme/custom, area, customized) or wp_navigation menus; entity plus id reads one as parsed blocks and content_hash. global_styles: theme/user/merged theme.json, variations, fonts (id: dot path narrows). Reports a classic themesite-templates-write: Edit a block theme template or part (id: slug or theme//slug) or wp_navigation menu (id). save: content or blocks, customizing over the theme file; add_block (content: one block)/update_block/remove_block: by path with expected_hash; revert: delete the customization. global_styles (no id): save attrs {dot.path: value|null} to user styles, preset entries by slug; variation: title; revert: reset. Snapshot-first
Free vs Pro
The split today
The plugin registers 407 abilities: 274 free and 133 Pro. Everything is GPL-2.0 licensed either way, the Pro tier gates which abilities register on your site, not the license of the code. The Tools Reference lists every one, generated from the plugin source.
The free tier includes the entire safety net and the broad site-management surface:
- The full safety engine: snapshot, apply, verify, rollback (both operation- and session-level), plus the wp-admin wpmcp history and one-click restore screen.
- All content, taxonomy, site search, Gutenberg block, and surgical block-editing tools, and the
build-pagecomposite. - Media (including stock-image search/import, sanitized SVG upload and uploads from raw bytes), settings, users, comments, navigation menus, plugins and themes, plus the theme builder for headers, footers and 404 pages.
- The core WooCommerce surface: products, variations, bulk updates, a two-step product import (
plan-product-import, thenapply-product-import), orders, notes, coupons, tax rates and sales reports. - SEO metadata through Yoast SEO, Rank Math, The SEO Framework, SureRank, SEOPress or Slim SEO, redirects (including the Redirection plugin’s own redirects) and broken-link checks, internal-link analysis, performance and security scanners.
- Backups with restore, site-wide find and replace, site URL rewrites, site-to-site archive push, and local-to-live change sets.
- The PHP snippet store (snippets are always stored inactive), the rendered page HTML reader, and Elementor CSS regeneration.
- Governance, scoped identities, the audit log, gateway credentials, the ability bridge, onboarding/connection tools, multisite reads, analytics/Search Console (through Site Kit), cron, maintenance mode, REST passthrough, and compact tool dispatch.
- The integration dispatcher pairs: ACF (values, plus field groups, ACF post types and ACF taxonomies), Meta Box, JetEngine and Pods fields, TranslatePress strings, BuddyPress groups, activity and profile fields (
plugin-data-read/plugin-data-write), Contact Form 7 with Flamingo entries, Forminator, SureForms and MetForm, events, donations and memberships, Polylang and WPML, and the theme pair (theme-read/theme-write) with the Astra and Kadence theme settings packs, child theme scaffolding, and read-only status for UpdraftPlus, Duplicator, Solid Security, MonsterInsights and W3 Total Cache plus the W3 Total Cache purge. - Operation history: the last 20 operations.
The 133 Pro abilities are:
- Elementor deep editing (33): widget, element, template, theme-template, popup, dynamic-tag, global color and typography, custom CSS and code-snippet tools, built on a curated 44-widget catalog with typed, validated settings schemas.
- Elementor structural suite (8):
add-container,update-container,duplicate-element,find-element,reorder-elements,set-element-label,update-page-settings,batch-update. - Elementor v4 (12): atomic elements (
add-atomic-widget,add-div-block,add-flexbox,update-atomic-widget), global classes (4) and global variables (4). - Custom widget builder (9) and custom block builder (8): build Elementor widgets and Gutenberg blocks from a validated data spec.
- Brand kits (4) and scoped custom CSS and opt-in custom JavaScript (2).
- Builders (3):
detect-builder,get-builder-contentandupdate-builder-content, covering Bricks, Divi, WPBakery, Beaver Builder, Breakdance, Oxygen 6, classic Oxygen, Avada and Thrive Architect. - Block suite packs (2):
block-suites-readandblock-suites-writefor Kadence Blocks, GenerateBlocks, Spectra, Otter Blocks and the Blocksy companion blocks, with pattern import from the registry or the WordPress.org Pattern Directory. - Content analysis (7): accessibility, SEO and contrast analysis plus fixes such as alt text from context, color contrast and link text.
- SEO depth (6): term-level SEO, social images and meta, and generated meta tags and JSON-LD schema.
- SEO data provider (1):
set-seo-data-key, which stores your own DataForSEO credentials (encrypted, never returned) for the keyword and backlink ops ofanalyze-seo. - WooCommerce operations catalog (3):
woo-ops,woo-read,woo-write: order create and edit, shipping zones and methods, webhooks, payment gateways (secrets masked), review moderation, totals reports, system status and brands, plus the raw catalog of wc/v3 routes. See WooCommerce Tools. - Forms adapter pack (10): read/write pairs for WPForms, Gravity Forms, Formidable, Ninja Forms and Fluent Forms: forms, fields, notifications, entries and entry status.
- WP MCP Cloud (12): settings sync, the widget and block marketplace, and cloud gateway provisioning and status.
- Project memory (3):
memory-recall,memory-propose,memory-save-summary. - Guarded execution (7):
run-wp-cli, the async WP-CLI jobs (4),run-php-snippetandactivate-php-snippet, all additionally default-off; see the safety model. - Stock placement (1):
insert-stock-image(searching and importing stock images stays free). - Media optimization (1):
optimize-media, which compresses Media Library JPEG and PNG images, caps dimensions and writes WebP and AVIF copies with the server’s own image editor, over the whole library in the background if asked, with one undo for the run. - Package install from ZIP (1):
install-package-from-zip(installing from the WordPress.org directory stays free).
Some Pro capabilities are operations inside a free dispatcher pair rather than abilities of their own, so they do not change the counts above: the Essential Addons, Premium Addons and Ultimate Addons suite packs, the GeneratePress and Blocksy theme settings packs, FunnelKit funnel reads and dynamic single, archive and search templates (all on theme-read / theme-write), ACF batch-update-fields, and All in One SEO support in the SEO tools. list-operations on each pair shows which operations this install offers.
Plus, on Pro: unlimited operation history instead of the 20-operation cap.
The Gate
Free/Pro gating lives in WPMCP\Pro\Gate: a single boolean, Gate::is_pro(), which asks the Freemius SDK’s can_use_premium_code() (an active paid licence or trial) when the SDK is loaded, and fails closed to false when the SDK is absent or answers anything other than a strict true (no fatal error either way). It deliberately does not use the __premium_only variant: the Pro code ships in the same tree and is gated at runtime, and Freemius’ free-build processor strips __premium_only call sites, which would corrupt the check in a free zip.
The MCP\Registrar skips registering any ability tagged 'pro' when Gate::is_pro() is false, so Pro tools do not appear in a free-tier site’s tool list. The other concrete difference is history retention. Snapshot_Store::history_limit() has no licence check: it returns 20 unless the public wpmcp_snapshot_history_limit filter says otherwise. The Pro build adds that filter itself, returning unlimited (PHP_INT_MAX) while the licence is active:
public static function limit($default): int
{
return Gate::is_pro() ? PHP_INT_MAX : (int) $default;
}
If a licence that was active ends, the site’s current history depth is held rather than pruned, and the admin shows a notice so the owner can trim it or choose a depth. A lapse never deletes undo points on its own.
Free tier: 20 operations of history by default, pruned after every write by whole sessions: the most recent run is always kept whole however large it is, and a run that has been dropped is refused by rollback-session with a reason rather than undone in part. Pro: unlimited while the licence is active. See Safety model for the detail.
Buying Pro
Pro is licensed through Freemius (annual plans from $26.99/year for a single site, with lifetime plans alongside). Buy on the pricing page; the licence activates in the plugin and the Pro abilities register from the next request. The free plugin is fully functional without one.
Privacy default: the Freemius opt-in
Bootstrap::config() keeps Freemius’ anonymous_mode off and pins enable_anonymous on, deliberately:
// anonymous_mode would suppress the SDK's stock opt-in screen and decide
// on the user's behalf, so it stays false and the SDK ships its
// default-off connect screen. Nothing is transmitted before the user
// affirmatively opts in.
'anonymous_mode' => false,
// The Skip link on the connect screen is what makes the opt-in
// declinable, so the value it depends on is stated here.
'enable_anonymous' => true,
So on activation Freemius shows its stock opt-in screen, which defaults to off and carries a Skip link. Skip or decline it and no connection is made, no licence data is exchanged, and the plugin keeps working. The one path that can still reach Freemius afterwards is the optional deactivation feedback form on the Plugins screen, which the plugin readme’s External services section spells out. Opting in later, from the WP MCP > Account page, is how a Pro licence is activated.
WooCommerce Tools
wpmcp treats a WooCommerce store as a first-class surface, not an afterthought bolted onto the content tools. An AI agent can read products, orders, and sales data, and make the day-to-day changes a shop owner actually asks for: updating a price, marking an order as shipped, adjusting stock. Every one of those changes goes through the same snapshot/rollback engine documented in The safety model, so a bad price edit or a wrong order-status change is a one-click undo, not a support ticket.
What a shop owner gets
- Read the whole store.
list-productsandget-productfor the catalog,list-product-categoriesfor how it is organized,list-ordersandget-orderfor what customers have bought,get-sales-reportfor a date-range summary of gross sales, order count, items sold, and top products by quantity. - Change products safely.
update-productedits price, stock, description, SKU, and status. A product is a WordPress post under the hood, so the change is snapshotted the same way an ordinary page edit is:rollback-operationputs the exact prior price and stock quantity back, not an approximation. - Change order status safely.
update-order-statusmoves an order through the store’s registered statuses (processing, completed, refunded, and so on), validated against what the store actually supports. It is snapshotted via a dedicatedwc_orderobject type, sorollback-operationrestores the prior status exactly, whether the store uses WooCommerce’s classic post-based orders or the newer High-Performance Order Storage (HPOS) tables. Every order tool is HPOS- and CPT-safe: it does not assume one storage backend, so the same tools work whether or not a store has migrated to HPOS. - Create products, and add order notes.
create-productandadd-order-noteare additive: a new product with no prior state to snapshot, or a note appended to an order’s history. A mistaken product is removed withdelete-product. - Variations, coupons and tax rates.
list-variations,create-variation,update-variationanddelete-variation;list-coupons,get-coupon,create-coupon,update-coupon,validate-couponanddelete-coupon;list-tax-rates,create-tax-rate,update-tax-rateanddelete-tax-rate. Bulk price and stock passes go throughbulk-update-products, andlist-low-stock-productsfinds what needs reordering.
Product import in two steps
plan-product-import is read-only: it validates every row, matches it to an existing product by SKU, and returns a plan in which each row is a create, an update (with a field-level diff), a skip (with a reason) or an error (with every problem found). Nothing is written, no image is fetched, and category and attribute terms must already exist. The plan carries a hash of the rows, the plan and the current state of every matched product.
apply-product-import writes exactly that plan. It rebuilds the plan first and refuses if anything moved in between (a matched product edited, a SKU taken, a category removed), refuses a plan with error rows, and needs confirm: true above its product threshold. Writes go through the same paths as the single-product tools, image URLs go through the guarded remote media download, and everything shares one session_id, so rollback-session undoes the whole import. A row that fails part way rolls back the whole session: an import is all or nothing. Both steps are free.
The Pro operations catalog
WP MCP Pro adds three abilities that reach much more of the store without adding a tool per endpoint: woo-ops lists the catalog (every op with its mode, route, capability, whether it needs confirm: true, and which snapshot backs it), woo-read runs read ops, and woo-write runs write and destructive ops, singly or as a batch under one session_id. Ops are named by domain, for example orders.update or shipping.add-method.
- Orders.
orders.createandorders.updaterun through WooCommerce’s order CRUD, so HPOS and the legacy post store both work. No payment gateway is ever called:set_paidandtransaction_idare refused, and the payment method is a plain label. An edit is snapshotted as the full order and rolls back exactly; a create is rolled back by trashing the order. Responses leave out order meta, the transaction id, and the customer IP and user agent. - Shipping. Zones (
shipping.create-zone,shipping.update-zone,shipping.delete-zone) and the three core methods, flat rate, free shipping and local pickup (shipping.add-method,shipping.update-method,shipping.remove-method), validated field by field against each method’s own settings form. Every write except a zone create is snapshotted as the whole zone; a create’s rollback deletes the zone, and only while it is still the zone that was created. Third-party methods are listed without their settings, which can hold carrier credentials. - Webhooks.
webhooks.create,webhooks.update,webhooks.pauseandwebhooks.delete. The signing secret is write-only and masked in every response, the delivery URL must be a public https address that passes an SSRF guard, customaction.*topics are refused, and a webhook always delivers as the user who made it. - Payment gateways.
gateways.listandgateways.getmask every key, secret, password, token, signature or credential field and every password-type field.gateways.updatechanges the enabled flag, title, description, order and non-secret settings, and refuses secret fields outright: the store admin screen stays the place to set a credential. Each write is snapshotted as the one option it changes, and restoring it takesmanage_woocommerce, because the snapshot holds the gateway’s secrets. - Reviews.
reviews.list(never the reviewer’s email or IP),reviews.approve,reviews.unapprove,reviews.spam,reviews.update,reviews.replyandreviews.trash. Every review op needsmoderate_commentsplusedit_producton the review’s product. Each change is snapshotted as the full comment with its rating and verified flag; a reply’s rollback trashes it. - Reports.
reports.sales(optionally by day, week or month),reports.top-sellers,reports.orders,reports.customersandreports.coupons, from WooCommerce’s analytics tables when they agree with the order store and from order queries otherwise. Aggregate figures only, never a customer’s name, email or address. - System status.
system-status.getreads the status report by section with secret-like values masked;system-status.toolslists the maintenance tools;system-status.run-toolruns an allowlisted one (clearing transients, regenerating lookup tables and similar). Tools that delete store rows needconfirm: true, and every run says why it cannot be rolled back. - Brands.
brands.list,brands.get,brands.create,brands.update,brands.delete,brands.assignandbrands.unassign, available when the store registers the brands taxonomy. - Everything else in the catalog: products, variations, coupons, customers, refunds, tax rates and classes, and store settings through the store’s own wc/v3 routes.
What is honestly not undoable: refunds.create is snapshotted but reports recoverable: false (the order status comes back, the money does not), status tools rebuild derived data and are not snapshotted, and plain creates report the op that removes what they made. Destructive ops are off until a site opts in with the wpmcp_woo_op_enabled filter and always need confirm: true.
The one-click undo, and why it matters here specifically
Most AI-for-WooCommerce integrations either refuse to touch products and orders at all, or let an agent write directly with no way back. That is a real risk on a live store: an agent that fat-fingers a price from $49 to $4.90, or flips a paid order to “refunded” by mistake, has just cost real money in the minutes before a human notices.
wpmcp’s answer is the same safety engine used everywhere else in the plugin:
update-productandupdate-order-statussnapshot the object before the change applies.- The change happens.
- If it turns out to be wrong,
rollback-operation(from the agent, or a one-click Restore button on the wpmcp wp-admin screen) restores the exact prior state: the old price, the old stock count, the old order status.
This is the detail worth underlining for anyone evaluating AI tools against a live store: product and order-status changes are undoable by construction, not by promise. Competing WooCommerce AI plugins that offer direct database or REST access typically have no equivalent undo path once a write lands; recovering means restoring from a nightly backup (losing every order placed since), or fixing it by hand from memory. wpmcp’s snapshot happens at the moment of the change, so the fix is a single click, seconds later, with no data loss for anything else that happened on the store in between.
Destructive and disabled-by-default tools
delete-productis disabled by default (a site must opt in via thewpmcp_enable_delete_productfilter) and always requiresconfirm: true. Trash is the default path;force: truepermanently deletes, and even that is snapshotted, a force-deleted product resurrects at its original ID with its price, stock, and category terms intact.
Capabilities
Read tools (list-products, get-product, list-product-categories, get-sales-report) and product writes require manage_woocommerce, matching WooCommerce’s own admin gate. Order tools (list-orders, get-order, update-order-status, add-order-note) require edit_shop_orders. The Pro catalog checks a capability per op before dispatch and is never looser than the free tool covering the same data: order, note and refund reads keep edit_shop_orders, customer reads need list_users and customer writes edit_users or create_users, review ops need moderate_comments plus edit_product, and everything else needs manage_woocommerce. The store endpoint’s own permission check still runs on top. It defers to the store’s existing WooCommerce roles, so a shop owner does not need to reason about a second permissions model.
See the WooCommerce section of the Tools reference for the full argument-level detail on every WooCommerce tool.
Contributing and Tests
Dev setup
composer install # install dev dependencies (PHPUnit, WP test scaffolding, phpcs)
composer test # run the full PHPUnit + WordPress integration suite
composer test:free # run only the free-tier test suite
composer test:pro # run only the Pro/Freemius test suite
composer lint # PSR-12 with WordPress-idiomatic naming, via phpcs
The suite needs a MySQL or MariaDB database for the WordPress integration harness (tests/bootstrap.php sets it up via the standard WordPress PHPUnit scaffolding). CI installs it with bin/install-wp-tests.sh wordpress_test root root 127.0.0.1 6.9 against a MariaDB 10.6 service container; see .github/workflows/ci.yml for the exact steps if you need to reproduce it locally.
CI runs on every push and pull request across a PHP 8.1 / 8.2 matrix: composer install, composer lint, install the WordPress test scaffolding, then composer test.
Test structure
Tests are split into two PHPUnit test suites, matching the free/Pro split described in Free vs Pro:
tests/free/, autoloaded asWPMCP\Tests\Free\, mirrors thesrc/structure:Admin/,Content/,MCP/,Media/,Safety/,Settings/,Tools/, plus root-level smoke and bootstrap tests. This is where the bulk of the coverage lives, including the safety engine’s heaviest tests (Safety/SafeMutationTest.php,Safety/RollbackServiceTest.php,Safety/SnapshotCaptureTest.php,Safety/SnapshotStoreCrudTest.php,Safety/SnapshotStoreInstallTest.php).tests/pro/, autoloaded asWPMCP\Tests\Pro\, covers the Pro ability surface:Elementor/,Builders/,Analysis/,Cli/,Code/,Compose/,Media/,Freemius/, plusGateTest.phpfor the gate itself.
phpunit.xml.dist wires both suites (free -> tests/free, pro -> tests/pro) and defines the WPMCP_TESTING constant used by the bootstrap files to skip the plugin’s normal ABSPATH guard during tests.
The safety invariant
The project’s core rule, stated plainly in the README’s Contributing section: no tool may write to the database except through Safe_Mutation::run(), and every change ships with a test.
This is not enforced by a single “no bypass” test; it’s enforced structurally and by convention across src/Tools/. Every WordPress write call (wp_update_post, wp_delete_post, wp_insert_post, update_option, etc.) in a tool handler either:
- sits inside a
Safe_Mutation::run()closure, or - has an explicit code comment justifying why it is exempt (only two categories qualify: pure-creation tools like
create-postandsideload-image, where there is nothing pre-existing to snapshot; and WordPress’s own trash fordelete-post’s default path anddelete-media’sMEDIA_TRASH-covered path, which is already reversible without a redundant snapshot).
When you add a new tool that mutates existing state, route the mutation through Safe_Mutation::run() with an object_type, object_id, session_id, and tool_name in its context array, the same pattern every existing write tool follows (see src/Tools/Content/Update_Post.php for a representative example, or src/Tools/Settings/Update_Settings.php for the per-key variant used by batch writes).
If a mutation genuinely creates a brand-new object with nothing to overwrite, or is already covered by WordPress’s own reversible trash, document that exemption inline with a comment, the same way the existing exempt tools do, so the next contributor (or reviewer) understands it was a deliberate decision and not an oversight.
How to document a new feature
When a new tool or test lands in this codebase:
- Add or extend a section in
40-tools-reference.mdfor the new tool: its registered ability name (wpmcp/<name>), purpose, key args, whether it’s safe-wrapped (and why, if not), and any capability or opt-in requirements (disabled-by-default filters,confirmflags, allowlists). - If it changes safety behavior, adds a new object type to snapshot/restore, changes pruning/retention logic, changes the meta-purge, or touches the force-delete/resurrection path, also update
30-safety-model.md. This file exists specifically to describe actual mechanics, so keep it in sync with the code rather than the aspirational design spec. - Prefer describing what the code does over what a design doc says it should do. This documentation set intentionally verified every claim against
src/directly; a design spec drifting out of date from the shipped implementation is a normal part of development, not a bug, but the docs here should track the code, not the spec. - If a feature is Pro-gated or merely planned, say so explicitly (“planned”) rather than implying it ships today. See
50-free-vs-pro.mdfor the current free/Pro boundary.