@adsim/wordpress-mcp-server
v6.2.1
Published
Enterprise WordPress MCP Server — 137 tools, modular architecture, governance, audit trail, WooCommerce, Schema.org, multilingual.
Downloads
1,707
Maintainers
Readme
WordPress MCP Server
Governance · Audit Trail · Multi-Site · No plugin for the core operations
The enterprise governance layer for Claude-to-WordPress integrations — secure, auditable, and multi-site.
v6.2.1 Enterprise · 137 tools · 1268 Vitest tests · GitHub Actions CI
Table of Contents
- Architecture
- Why This Server
- Safety Model
- Data Retention
- Quick Start
- HTTP Streamable Transport
- MCPB Bundle
- Available Tools (137)
- Enterprise Controls
- MU-Plugin Companion
- SEO Metadata
- WooCommerce Setup
- Testing
- Structured Audit Log
- Multi-Target
- Health & Reliability
- Security
- Troubleshooting
- Development
- Changelog
- Roadmap
- Contributing
- License
- Credits
Architecture
┌─────────────────────────────┐
│ Claude Client │ Claude Desktop · Claude Code · Any MCP client
└──────────────┬──────────────┘
│ MCP Protocol (stdio or HTTP Streamable)
┌──────────────▼──────────────┐
│ WordPress MCP Server │ Node.js · Standalone · No plugin for core operations
├─────────────────────────────┤
│ index.js (~498 lines) │ Orchestration only: MCP transport, enterprise controls, dispatch
├─────────────────────────────┤
│ src/tools/ (18 modules) │ 180 tool definitions + handlers by category
├─────────────────────────────┤
│ src/shared/ │ utils · api · audit · governance · context
├─────────────────────────────┤
│ src/plugins/ │ PluginRegistry · ACF · auto-detected via REST namespaces
├─────────────────────────────┤
│ Tool Profile Filter │ editorial by default · shop · site · maintenance · all
├─────────────────────────────┤
│ Execution Controls │ Read-only · Draft-only · Plugin mgmt · Type/status allowlists
├─────────────────────────────┤
│ Audit Logging │ JSON on stderr · 79+ instrumentation points
├─────────────────────────────┤
│ Rate Limiting │ Client-side · Configurable per-minute cap
├─────────────────────────────┤
│ HTTP Transport │ Bearer auth · Session management · Origin validation
└──────────────┬──────────────┘
│ HTTPS + WordPress Application Password (Basic Auth over TLS)
┌──────────────▼──────────────┐
│ WordPress REST API │ Single site or multi-target
├─────────────────────────────┤
│ MCP Diagnostics mu-plugin │ Optional · Debug log · Cron · Schema · Security endpoints
└─────────────────────────────┘Why This Server
Most WordPress MCP servers focus on what you can do. This one focuses on what you should be allowed to do — and who can verify it happened.
In regulated environments — financial services, healthcare, legal, government — AI-powered content operations need guardrails. This server supplies a governance layer: read-only and draft-only modes, an approval workflow, dry-run previews, before/after diffs, undo, and a sequenced, hash-chained audit trail.
It is one component, not a compliance product. Read the Safety Model before quoting it in a tender: the controls live in this process, the audit log needs somewhere durable to land, and the security boundary remains the WordPress account you give it.
No MCP plugin required. Posts, pages, media, taxonomies, comments, users and revisions work against a standard WordPress with nothing added for this server. What the rest needs is what you would expect: WooCommerce tools need WooCommerce, SEO tools need an SEO plugin and its fields exposed over REST (see SEO Metadata), multilingual tools need WPML, Polylang or TranslatePress, PageSpeed and WPScan checks need their API keys. The durable change journal, the debug log, file permissions, database diagnostics and schema injection need the companion mu-plugin — one file, no composer, no build.
The promise is that nothing MCP-specific has to be installed to start working, not that 137 tools run on a bare WordPress.
With 137 tools across 21 categories, agencies load only what a deployment needs: the editorial profile is the default, shop, site, maintenance and all cover the rest, and WP_TOOL_CATEGORIES picks categories directly. Beyond narrowing ListTools from ~16.2k to ~4-12k tokens, a profile stops user management, plugin activation and file-permission tools being offered to an agent that only writes articles — and with WP_TOOL_ENFORCE_PROFILE=true it refuses them outright rather than merely hiding them.
Safety Model
These controls are operational guardrails, not a security boundary. They are enforced pre-flight inside the MCP server process, which protects against agent error — the dominant risk in practice — but not against an operator. Anyone who can relaunch the server can relaunch it with different environment variables. The security boundary remains the capabilities of the WordPress account behind the Application Password: scope that account to what the deployment actually needs, and treat the controls below as defence in depth on top of it.
- Deletes go to the trash by default — a permanent delete needs
force=true. Blocking deletion outright (WP_DISABLE_DELETE) and requiring a signed confirmation (WP_CONFIRM_DESTRUCTIVE) are off unless you turn them on - Configurable execution modes — read-only, draft-only, or full access per deployment
- Pre-flight enforcement — all guardrails checked before any API call is made
- Audit trail — every action logged with timestamp, target, outcome and latency, as structured JSON on stderr. Entries are sequenced and hash-chained; with
WP_MCP_SECRETset the chain is keyed with HMAC-SHA-256. That detects alteration, loss and reordering — see Sequence and hash chain. It does not make stderr immutable storage, and there is no delivery guarantee: ship it somewhere append-only if you need one - Credential isolation — secrets never appear in logs or error outputs
- Multi-tenant ready — independent auth and config per WordPress target
Data Retention
There are three levels, and they are worth keeping apart.
1 — The server process writes nothing to disk. No cache, no database, no state file. That is true unconditionally. Audit logs go to stderr in real time and can be disabled (WP_AUDIT_LOG=off) or redirected to any pipeline.
2 — One thing is held in memory: the change journal. To let you undo a write, the server keeps the previous value of the fields that write changed — the last 20 by default, oldest dropped, gone when the process ends. WP_CHANGE_JOURNAL=off disables it; a number resizes it. An entry too large to restore safely is refused rather than truncated, and says why.
3 — With the companion installed, those snapshots are also stored in WordPress. They then survive a restart and are visible from another machine. This is real persistence, and it belongs in your data map — but it lands in the same database the content came from, not in a second place under our control. The companion prunes after 30 days or 500 entries. WP_CHANGE_JOURNAL_DURABLE=off opts out.
Everything else is stateless: content flows through the server and is not retained beyond the tool call that fetched it.
Before 5.9 this section claimed zero retention outright. Undo is not possible without keeping something. 6.2 added the durable half, so the claim is now split three ways rather than stated as an absolute.
Quick Start
Requirements
- Node.js >= 20 — tested on 20, 22 and 24
- WordPress site with REST API enabled (default since WP 4.7)
- WordPress Application Password (WP 5.6+)
- HTTPS endpoint (required for production)
- WooCommerce 3.5+ (optional, for WooCommerce tools)
Install from npm
Published as @adsim/wordpress-mcp-server.
Nothing to install: MCP clients launch the server themselves, and npx fetches it on
first use.
npx -y @adsim/wordpress-mcp-serverPin a version for anything that matters. A governance component that silently moves under you is a governance component you cannot vouch for: a new release can change which tools exist, what the defaults refuse, and what a workflow does. Shared agency configs, CI and client work should name a version:
npx -y @adsim/[email protected]Unpinned is fine for trying it out or for a throwaway session — it always resolves the latest release:
npx -y @adsim/wordpress-mcp-serverInstall globally only if you intend to run it by hand:
npm install -g @adsim/wordpress-mcp-server
wordpress-mcp-server --verboseThe published package holds the runtime and nothing else — 44 files, no tests, no build
tooling. Requires Node 20 or later; the version is enforced by engines, so npm warns you
on an older runtime rather than failing obscurely later.
Install from GitHub
Use the repository when you want to read the tests, change something, or run an unreleased commit. github.com/GeorgesAdSim/wordpress-mcp-server
git clone https://github.com/GeorgesAdSim/wordpress-mcp-server.git
cd wordpress-mcp-server
npm install
npm testEvery release is tagged, so a specific version is one checkout away:
git checkout v6.2.1| What | Where | |---|---| | Releases and tags | /releases | | Report a bug | /issues | | Report a vulnerability | SECURITY.md — privately, not in an issue | | Trademarks and forks | TRADEMARK.md |
Point a client at a clone with an absolute path instead of npx:
{ "command": "node", "args": ["/absolute/path/to/wordpress-mcp-server/index.js"] }Useful scripts:
npm test # unit suite — no network calls, fully mocked
npm run integration:up # disposable WordPress in Docker
npm run test:integration # real HTTP against it
npm run integration:down # tear it down, volumes included
npm run check:metadata # fails if any published figure has drifted from the code
npm run build:mcpb # build the Claude Desktop bundle
npm run verify:mcpb # unpack it and boot the server out of it
npm run verify:package # install the npm tarball in a clean project and boot itConfigure
Create a .env file:
WP_API_URL=https://yoursite.com
WP_API_USERNAME=your-username
WP_API_PASSWORD=xxxx xxxx xxxx xxxx xxxx xxxx
# Optional: WooCommerce (generate at WooCommerce → Settings → Advanced → REST API)
WC_CONSUMER_KEY=ck_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
WC_CONSUMER_SECRET=cs_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# Tool surface (optional — defaults to the editorial profile)
WP_TOOL_PROFILE=editorial # editorial · shop · site · maintenance · all
WP_TOOL_CATEGORIES=seo,content,schema # Pick categories directly, wins over the profile
WP_COMPACT_JSON=true # Compact JSON output (default)To generate an Application Password: WordPress Admin → Users → Profile → Application Passwords → Add New.
Connect to Claude Desktop
Add to claude_desktop_config.json:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"wordpress": {
"command": "npx",
"args": ["-y", "@adsim/wordpress-mcp-server"],
"env": {
"WP_API_URL": "https://yoursite.com",
"WP_API_USERNAME": "your-username",
"WP_API_PASSWORD": "xxxx xxxx xxxx xxxx xxxx xxxx"
}
}
}
}Connect to Claude Code
claude mcp add wordpress \
-e WP_API_URL=https://yoursite.com \
-e WP_API_USERNAME=your-username \
-e WP_API_PASSWORD="xxxx xxxx xxxx xxxx xxxx xxxx" \
-- npx -y @adsim/wordpress-mcp-serverHTTP Streamable Transport
New in v3.0.0 — Run the server over HTTP instead of (or alongside) stdio, following the MCP spec 2025-03-26.
Start in HTTP mode
MCP_TRANSPORT=http \
MCP_HTTP_PORT=3000 \
MCP_AUTH_TOKEN=your-secret-token \
WP_API_URL=https://yoursite.com \
WP_API_USERNAME=your-username \
WP_API_PASSWORD="xxxx xxxx xxxx xxxx" \
npx -y @adsim/wordpress-mcp-serverDual mode (stdio + HTTP simultaneously)
MCP_TRANSPORT=http \
MCP_DUAL_MODE=true \
MCP_AUTH_TOKEN=your-secret-token \
npx -y @adsim/wordpress-mcp-serverHTTP environment variables
| Variable | Default | Description |
|-----------------------|-------------|------------------------------------------------------|
| MCP_TRANSPORT | stdio | Set to http to enable HTTP Streamable transport |
| MCP_HTTP_PORT | 3000 | HTTP server port |
| MCP_HTTP_HOST | 127.0.0.1 | Bind address |
| MCP_AUTH_TOKEN | (none) | Bearer token for authentication (required in HTTP mode) |
| MCP_ALLOWED_ORIGINS | (none) | Comma-separated allowed origins (anti-DNS-rebinding) |
| MCP_SESSION_TIMEOUT_MS | 3600000 | Session TTL in milliseconds (1 hour) |
| MCP_DUAL_MODE | false | Run stdio and HTTP transports simultaneously |
Health check
curl http://localhost:3000/health
# → { "status": "ok", "version": "6.2.1", "transport": "http" }Connect an MCP client via HTTP
{
"mcpServers": {
"wordpress-http": {
"url": "http://localhost:3000/mcp",
"headers": {
"Authorization": "Bearer your-secret-token"
}
}
}
}MCPB Bundle — Claude Desktop One-Click Install
New in v3.1.0 — Package the server as a
.mcpbbundle for Claude Desktop distribution.
The bundle stores WordPress credentials securely in the OS keychain (sensitive: true) — no manual JSON editing required.
Build the bundle
npm run build:mcpb
# → wordpress-mcp-server.mcpbInstall in Claude Desktop
Double-click wordpress-mcp-server.mcpb — Claude Desktop will prompt for:
- WordPress Site URL
- WordPress Username
- WordPress Application Password (stored in OS keychain)
Available Tools (137)
Reading the numbers
Several counts appear in this document and they are not the same count.
| | Count | What it is |
|---|---|---|
| Definitions in the code | 180 | Everything declared, retired names included |
| Retired but still routable | 43 | Absent from ListTools, still answer when called by name |
| Advertised | 137 | The most ListTools can offer — the headline figure |
| Conditional | 29 | Withheld until their own switch is on: 20 WooCommerce (WC_CONSUMER_KEY), 3 approval (WP_REQUIRE_APPROVAL), 6 plugin intelligence (WP_ENABLE_PLUGIN_INTELLIGENCE) |
| Profile all, out of the box | 108 | 137 − 29 |
| Profile editorial, out of the box | 68 | What a fresh install shows |
How 6.0 got from one catalogue to the other:
178 advertised before 6.0
− 43 names retired (21 audits, 22 Full Site Editing)
+ 2 tools that replaced them (wp_audit, wp_site_design)
= 137The 6.0 changelog reported the 43 removals and not the 2 additions, which made the
subtraction look wrong. Today's 180 definitions already include both, so 180 − 43 = 137
falls out directly.
Three kinds of conditionality, which the table above does not distinguish and which account for the rest of the questions people ask:
| Kind | Effect | Examples |
|---|---|---|
| Gated in ListTools | Not offered at all until the switch is on | The 29 above |
| Offered but degraded | Always listed; returns less without a key | wp_audit_page_speed without PAGESPEED_API_KEY, wp_audit_plugin_vulnerabilities without WPSCAN_API_KEY |
| Appears on detection | Added at runtime when the plugin's REST namespace is found | ACF and Elementor tools, counted separately from the 137 |
| Listed but needs the companion | Listed and callable; fails cleanly without the mu-plugin | Debug log, file permissions, database diagnostics, durable journal |
Registry-level figures — 180, 43, 137, 29 — are generated and checked by
npm run check:metadata, which fails CI when they drift. The profile counts are measured
and written by hand, because they depend on runtime configuration rather than on the
registry.
Content Management (13)
| Tool | Description |
|-------------------|------------------------------------------------------------------------------------------------|
| wp_list_posts | List posts with pagination, filtering by status/category/tag/author, and search |
| wp_get_post | Get a post by ID with full content, meta fields, and taxonomy info |
| wp_create_post | Create a post (defaults to draft). Supports HTML, categories, tags, featured image, meta |
| wp_update_post | Update any post field. Only provided fields are modified |
| wp_delete_post | Move to trash by default. Permanent deletion requires force=true. Confirmation token when WP_CONFIRM_DESTRUCTIVE=true |
| wp_search | Full-text search across all content types |
| wp_list_pages | List pages with hierarchy (parent/child), templates, and menu order |
| wp_get_page | Get page content, template, and hierarchy info |
| wp_create_page | Create a page with parent, template, and menu_order support |
| wp_update_page | Update any page field |
| wp_validate_block_structure | Validate Gutenberg block HTML before saving. Detects unclosed blocks, malformed JSON, invalid nesting, deprecated blocks |
| wp_bulk_update | Bulk update content across multiple posts/pages. Supports text replacement, meta updates, status changes, content append. Dry-run by default |
| wp_get_post_meta | Read post meta fields. Use for ACF data if acf/v3 unavailable, or for any custom meta (_elementor_data, _yoast_wpseo_*). Returns all meta if meta_key omitted |
Media Library (3)
| Tool | Description |
|-------------------|--------------------------------------------------------------------------|
| wp_list_media | Browse media with type filtering (image/video/audio/document) |
| wp_get_media | Get URL, dimensions, alt text, caption, and all available sizes |
| wp_upload_media | Upload a file from a public URL to the WordPress media library |
Taxonomies & Structure (5)
| Tool | Description |
|--------------------------|----------------------------------------------------------------------|
| wp_list_categories | List categories with hierarchy, post count, and descriptions |
| wp_list_tags | List tags with post count |
| wp_create_taxonomy_term| Create a new category or tag |
| wp_list_post_types | Discover all registered post types (including custom ones) |
| wp_list_custom_posts | List content from any custom post type (products, portfolio, events) |
Engagement (2)
| Tool | Description |
|---------------------|--------------------------------------------------------|
| wp_list_comments | List comments with filtering by post, status, and author |
| wp_create_comment | Create a comment or reply on any post |
Users & Security (10)
New in v4.7.0 — Full user CRUD, role/capability inspection, password reset, and application password management.
| Tool | Description |
|-------------------------------------|--------------------------------------------------------------------------------------------|
| wp_list_users | List users with roles, search, pagination. Supports full/summary/ids_only modes |
| wp_get_user | Full user profile: login, email, role, meta, registration date, avatar |
| wp_create_user | Create user with username, email, password, role. Requires confirm=true. Write |
| wp_update_user | Update email, display_name, role, bio, meta. Write |
| wp_delete_user | Delete user with mandatory post reassignment. Requires confirm=true. Blocked by WP_DISABLE_DELETE |
| wp_list_user_roles | All available roles with their capabilities listed |
| wp_get_user_capabilities | Active capabilities for a specific user |
| wp_reset_user_password | Trigger password reset email. Requires mu-plugin companion. Write |
| wp_list_user_application_passwords| List app passwords with name, UUID, created date, last used. Read-only |
| wp_revoke_application_password | Revoke an application password by UUID. Write |
SEO Metadata (2)
Auto-detects Yoast, RankMath, SEOPress, AIOSEO.
| Tool | Description |
|---------------------|----------------------------------------------------------------------------------------------|
| wp_get_seo_meta | Read SEO title, description, focus keyword, canonical, robots, Open Graph |
| wp_update_seo_meta| Update SEO metadata with automatic plugin detection |
Audits (1) — consolidated in v6.0
One tool, one check per call. Twenty-one separate audit tools used to differ only by which check they ran; folding them here leaves the model one decision instead of twenty-one. Their original names are no longer advertised but remain callable, so existing scripts keep working.
| Check | What it looks for |
|---|---|
| seo | Site-wide SEO metadata quality, scored 0-100, with missing fields |
| media_seo | Missing alt text, oversized images, filename quality |
| orphan_pages | Published content no internal link points to |
| heading_structure | H1-H6 hierarchy of one post, keyword placement |
| thin_content | Posts below a word count, weighted by age |
| canonicals | Missing, self-referencing or staging-domain canonicals |
| eeat_signals | Author bio, dates, citations, outbound authority |
| broken_internal_links | Internal links returning 404 or redirecting |
| keyword_cannibalization | Posts competing on the same intent (TF-IDF + cosine) |
| taxonomies | Empty, duplicated or near-duplicate terms |
| outbound_links | External profile: low-authority domains, missing nofollow |
| translation_coverage | Untranslated content per language |
| missing_seo_translations | SEO fields present in the source but absent in translations |
| readability | Sentence length, passive voice, transition words |
| update_frequency | Content gone stale past a threshold |
| anchor_texts | Generic, repeated or over-optimised anchors |
| schema_markup | Presence and validity of JSON-LD |
| content_structure | Section balance, list and media density |
| duplicate_content | Near-duplicate posts by cosine similarity |
| content_gaps | Taxonomy terms with too little content |
| cta_presence | Posts without a call to action |
wp_audit(check, post_type?, limit?, post_id?, options?). options carries the settings
specific to a check — min_words for thin_content, similarity_threshold for
duplicate_content, authoritative_domains for eeat_signals.
Schema.org Intelligence (7) — New in v4.9
Generation + injection + local validation end-to-end.
| Tool | Description |
|----------------------------------|--------------------------------------------------------------------------------------------|
| wp_generate_schema_article | Generates Article JSON-LD from post data with _embed for author and featured image |
| wp_generate_schema_faq | Detects Q&A from Gutenberg FAQ blocks, RankMath, AIOSEO, <details>, or H3+paragraph |
| wp_generate_schema_howto | Detects steps from ordered lists or numbered headings. Extracts totalTime, estimatedCost |
| wp_generate_schema_localbusiness| Pulls business data from ACF, Yoast Local SEO, or WP options |
| wp_generate_schema_breadcrumb | Rebuilds full breadcrumb hierarchy: Home > Category/Parent > Post |
| wp_inject_schema | Injects JSON-LD into _custom_schema_jsonld post meta. Supports dry_run=true. Requires mu-plugin |
| wp_validate_schema_live | Fetches live URL, extracts all JSON-LD blocks, validates structure and required fields |
Content Intelligence (8) — New in v4.4
All read-only, always allowed regardless of governance flags.
| Tool | Description |
|-------------------------------|------------------------------------------------------------------------------------------|
| wp_get_content_brief | Editorial brief aggregator: SEO + structure + links in 1 call |
| wp_extract_post_outline | H1-H6 outline extraction with category-level pattern analysis |
| wp_build_link_map | Internal link matrix with simplified PageRank scoring (0-100) |
| wp_extract_faq_blocks | FAQ inventory: JSON-LD, Gutenberg blocks, HTML patterns |
| wp_extract_entities | Regex/heuristic named entity extraction (brands, locations, persons, organizations) |
| wp_get_publishing_velocity | Publication cadence by author/category with trend detection |
| wp_compare_revisions_diff | Textual diff between revisions with amplitude scoring |
| wp_list_posts_by_word_count | Posts sorted by length with 6-tier segmentation |
Editorial Intelligence (6) — New in v4.13
Batch processing up to 500 posts, reuses TF-IDF engine. All read-only.
| Tool | Description |
|----------------------------------|------------------------------------------------------------------------------------------|
| wp_suggest_content_updates | Finds stale posts needing updates. Prioritizes by age, outdated date references, thin content |
| wp_audit_author_consistency | Profiles each author: post count, avg word count, frequency, readability, media usage |
| wp_build_editorial_calendar | Analyzes 12 months of history for seasonality, best days, scheduled posts, gaps |
| wp_find_pillar_content_gaps | Identifies topics with 3+ posts without a dedicated pillar page |
| wp_audit_internal_link_equity | Builds link graph, identifies orphans, over-linked pages, equity distribution 0-100 |
| wp_suggest_content_cluster | Clusters content by TF-IDF + cosine similarity around a keyword or post_id seed |
Multilingual Intelligence EU (4) — New in v4.10
WPML · Polylang Pro · Polylang Free (hreflang fallback) · TranslatePress.
| Tool | Description |
|-----------------------------------|----------------------------------------------------------------------------------------|
| wp_detect_multilingual_plugin | Auto-detects WPML > Polylang Pro > Polylang Free > TranslatePress |
| wp_list_languages | Lists configured languages with code, name, locale, URL prefix, flag |
| wp_get_post_translations | Gets all translations with post IDs, titles, URLs, statuses, SEO meta per language |
| wp_sync_seo_meta_translations | Copies SEO meta from source to translations. dry_run=true by default. Write |
Performance & Core Web Vitals (6) — New in v4.9
| Tool | Description |
|--------------------------------------|----------------------------------------------------------------------------------------|
| wp_audit_page_speed | Google PageSpeed Insights: Core Web Vitals (LCP, CLS, INP, FCP, TTFB), score, opportunities. Requires PAGESPEED_API_KEY |
| wp_find_render_blocking_resources | Detects render-blocking <link> and <script> in <head> (excludes defer/async) |
| wp_audit_image_optimization | Media library audit: non-WebP, large files (>100KB), missing alt text |
| wp_check_caching_status | Detects caching plugins (WP Rocket, W3TC, LiteSpeed) and cache HTTP headers |
| wp_audit_database_bloat | Revisions, expired transients, auto-drafts, spam, orphan postmeta. Requires mu-plugin |
| wp_get_plugin_performance_impact | Ranks active plugins by estimated performance impact (~50 plugin database) |
Security Audit (6) — New in v4.11
All read-only. Optional WPSCAN_API_KEY for CVE data.
| Tool | Description |
|----------------------------------|------------------------------------------------------------------------------------------|
| wp_audit_user_security | Audits admin accounts: default usernames, inactive accounts, generic emails, missing 2FA |
| wp_check_file_permissions | Checks wp-config.php, .htaccess, uploads/ permissions. Requires mu-plugin |
| wp_list_recently_modified_files| Recently modified files with suspicious detection: PHP in uploads, hex filenames |
| wp_audit_plugin_vulnerabilities| Scans plugins against WPScan API. CVEs with CVSS scores. Without API key: version list |
| wp_check_ssl_certificate | TLS validation (expiry, issuer, SAN), security headers (HSTS, CSP). Grades A+ to F |
| wp_audit_login_security | Login security score /100: XML-RPC, user enumeration, 2FA, brute force protection |
Site Health & Diagnostics (8) — New in v4.7
wp_get_debug_log and wp_get_active_hooks require mu-plugin companion.
| Tool | Description |
|----------------------------|----------------------------------------------------------------------------------------|
| wp_get_site_health_status| Overall health score (good/recommended/critical) with issue counts by severity |
| wp_list_site_health_issues| All health issues with label, description, severity, and badge |
| wp_get_site_health_info | System info: PHP version, MySQL, memory limit, extensions, WP constants |
| wp_get_debug_log | Read last N lines of debug.log filtered by level. Max 500 lines. Requires mu-plugin |
| wp_get_cron_events | List all WP-Cron events with hook, schedule, next run, and overdue detection |
| wp_get_transients | List database transients with key, expiration, size. Filter by expired/active |
| wp_check_php_compatibility| Check each plugin's PHP version requirement vs current PHP |
| wp_get_active_hooks | Inventory of registered actions and filters with callbacks and priorities. Requires mu-plugin |
Site Design — FSE (1) — consolidated in v6.0
Twenty-two tools that were list/get/create/update/delete repeated across five resource types. Pure CRUD, so the resource became a parameter. The original names are no longer advertised but remain callable.
wp_site_design(action, resource, id?, options?)
| Resource | Actions | What it is |
|---|---|---|
| template | list · get · create · update · delete | Page-level layouts: single, archive, 404, front-page |
| template_part | list · get · create · update · delete | Reusable fragments: header, footer |
| global_styles | list · get · update | Theme design tokens: palette, typography, spacing. list returns the theme's style variations |
| block_pattern | list · get · create · delete | Block compositions offered in the editor. WordPress has no update |
| navigation_menu | list · get · create · update · delete | Block-based menus |
Reads are always allowed. create and update are refused by WP_READ_ONLY, delete
also by WP_DISABLE_DELETE — the tool gates itself per action rather than being refused
whole, so a read-only deployment can still inspect a theme.
Full Site Editing applies to block themes only. A site built with Elementor or a classic theme has no block templates; use the widgets tools below and the Elementor plugin layer.
Widgets (4)
Sidebar widgets belong to the classic theme system, not to Full Site Editing — they were
filed under fse until v6.0, which hid four classic-theme tools behind a block-theme
label. They now have their own category, in the site profile.
| Tool | Description |
|---|---|
| wp_list_widgets | List widgets, filterable by sidebar |
| wp_get_widget | Read a single widget |
| wp_update_widget | Update settings or move to another sidebar. Write |
| wp_delete_widget | Delete a widget. Blocked by WP_DISABLE_DELETE |
Plugin Intelligence Layer (up to 7) — New in v4.5-v4.6
Activates only when plugin detected via REST namespace discovery. Disable all: WP_DISABLE_PLUGIN_LAYERS=true
ACF (Advanced Custom Fields) — requires /acf/v3 namespace
| Tool | Description |
|----------------------|--------------------------------------------------------------------------|
| acf_get_fields | Get ACF custom fields for a post/page with key filtering and raw/compact/summary modes |
| acf_list_field_groups | List all configured ACF field groups |
| acf_get_field_group| Get full detail of an ACF field group by ID |
| acf_update_fields | Update ACF custom fields. Write — blocked by WP_READ_ONLY |
Elementor — requires /elementor/v1 namespace
| Tool | Description |
|-----------------------------|------------------------------------------------------------------------|
| elementor_list_templates | List Elementor templates (page, section, block, popup) |
| elementor_get_template | Get full template content and elements. Context-guarded at 50k chars |
| elementor_get_page_data | Elementor editor data: widgets used, elements count |
Plugin Intelligence (6) — New in v4.5
Requires WP_ENABLE_PLUGIN_INTELLIGENCE=true. Read-only (except write modes noted).
| Tool | Description |
|---------------------------|------------------------------------------------------------------------------------------|
| wp_get_rendered_head | Fetch real <head> HTML via RankMath/Yoast headless endpoint. Compare rendered vs stored |
| wp_audit_rendered_seo | Bulk rendered-vs-stored SEO divergence detection with per-post scoring |
| wp_get_pillar_content | Read or set RankMath cornerstone/pillar flag. Write blocked by WP_READ_ONLY |
| wp_audit_schema_plugins | Validate JSON-LD from SEO plugin native fields (rank_math_schema or yoast_head_json) |
| wp_get_seo_score | Read RankMath native SEO score (0-100) with bulk mode distribution stats |
| wp_get_twitter_meta | Read/write Twitter Card meta for RankMath, Yoast, SEOPress. Write blocked by WP_READ_ONLY |
Plugins & Themes (5)
| Tool | Description |
|-----------------------|--------------------------------------------------------------------------------------|
| wp_list_plugins | List installed plugins with status, version, author. Requires activate_plugins |
| wp_activate_plugin | Activate a plugin. Blocked by WP_READ_ONLY and WP_DISABLE_PLUGIN_MANAGEMENT |
| wp_deactivate_plugin| Deactivate a plugin. Blocked by WP_READ_ONLY and WP_DISABLE_PLUGIN_MANAGEMENT |
| wp_list_themes | List installed themes with active theme detection |
| wp_get_theme | Get theme details by stylesheet slug |
Revisions (4)
| Tool | Description |
|----------------------|------------------------------------------------------------------------------------------|
| wp_list_revisions | List revisions of a post or page (metadata only) |
| wp_get_revision | Get a specific revision with full content |
| wp_restore_revision| Restore a post to a previous revision |
| wp_delete_revision | Permanently delete a revision. Blocked by WP_READ_ONLY, WP_DISABLE_DELETE, WP_CONFIRM_DESTRUCTIVE |
Editorial Workflow & Visual Staging (9) — v3.2 / v4.15 / v5.1
Requires WP_REQUIRE_APPROVAL=true.
| Tool | Description |
|------------------------|--------------------------------------------------------------------------|
| wp_submit_for_review | Transition a draft post to pending status (author action) |
| wp_approve_post | Transition a pending post to publish (editor/admin action) |
| wp_reject_post | Return a pending post to draft with a mandatory rejection reason |
Visual Staging (5) — New in v4.15. Requires WP_VISUAL_STAGING=true for interception.
| Tool | Description |
|------|-------------|
| wp_create_staging_draft | Clone a published page/post into a shadow draft for safe editing |
| wp_list_staging_drafts | List all pending staging drafts, optionally filtered by source |
| wp_get_staging_preview_url | Get native WordPress preview URL for a staging draft |
| wp_merge_staging_to_live | Merge validated staging draft content to the live page (two-step) |
| wp_discard_staging_draft | Permanently delete a staging draft without touching the live page |
Workflow Orchestrator (1) — New in v5.1.
| Tool | Description |
|------|-------------|
| wp_run_workflow | Execute named or custom tool sequences in a single call. Built-in: seo_audit_and_stage, site_health_report, content_publish_safe, wc_product_audit |
Internal Link Intelligence (2) — New in v3.3
| Tool | Description |
|-----------------------------|----------------------------------------------------------------------------------------|
| wp_analyze_links | Audit all internal/external links in a post. HEAD verification per link |
| wp_suggest_internal_links | Semantic link suggestions scored by category, freshness, SEO keyword, title match |
WooCommerce Core (6) — New in v3.4
Requires WC_CONSUMER_KEY and WC_CONSUMER_SECRET.
| Tool | Description |
|---------------------|--------------------------------------------------------------------------------------|
| wc_list_products | List products with filtering by status, category, search, and sorting |
| wc_get_product | Get product by ID with full details and variations summary |
| wc_list_orders | List orders with filtering by status, customer, and date |
| wc_get_order | Get order by ID with line items, shipping, billing, and payment details |
| wc_list_customers | List customers with search and role filtering |
| wc_price_guardrail| Analyze a price change for safety (read-only). Returns safe/unsafe |
WooCommerce Intelligence (4) — New in v3.5
| Tool | Description |
|---------------------------|------------------------------------------------------------------------------------|
| wc_inventory_alert | Identify low-stock and out-of-stock products below threshold, sorted by urgency |
| wc_order_intelligence | Customer purchase history: lifetime value, average order, favourite products |
| wc_seo_product_audit | Audit product listings for SEO issues (descriptions, images, alt text, slugs) |
| wc_suggest_product_links| Suggest WooCommerce products to link from blog posts based on keyword relevance |
WooCommerce Advanced Intelligence (7) — New in v4.12
All read-only.
| Tool | Description |
|-------------------------------------|------------------------------------------------------------------------------------|
| wc_audit_product_seo | Product SEO score /100: title, description, slug, image alt, schema presence |
| wc_find_abandoned_carts_pattern | Abandoned cart patterns: hourly/daily trends, top products, revenue loss |
| wc_audit_checkout_friction | Checkout friction score 0-10: guest checkout, required fields, coupon, multi-step |
| wc_get_product_performance | Product metrics with trend comparison: units sold, revenue, refund rate |
| wc_audit_stock_alerts | Out-of-stock and low-stock audit with last sale dates. Includes variations |
| wc_find_duplicate_products | Duplicates by SKU, title/slug Levenshtein similarity. Union-find grouping |
| wc_audit_pricing_consistency | Pricing errors: sale >= regular, zero sale, minimal discounts, expired sales |
WooCommerce Write (3) — New in v3.6
All blocked by WP_READ_ONLY.
| Tool | Description |
|-----------------------|--------------------------------------------------------------------------------------|
| wc_update_product | Update product fields. Subject to wc_price_guardrail threshold enforcement |
| wc_update_stock | Update stock quantity of a product or variation |
| wc_update_order_status| Transition order status (e.g., processing → completed) |
Operations (5)
| Tool | Description |
|------------------------|--------------------------------------------------------------------------------------|
| wp_set_target | Switch active WordPress site in multi-target mode |
| wp_site_info | Site info, current user, post types, enterprise controls, tool_categories, plugin_layer |
| wp_get_site_options | Read WordPress site settings (title, tagline, language, timezone) via /wp/v2/settings |
| wp_list_changes | What writes changed during this session, and whether each can be undone |
| wp_rollback_change | Undo a listed change, restoring the fields it modified to their previous values |
Enterprise Controls
Configure execution policy via environment variables. All restrictions are enforced before any API call is made.
| Control | Default | Effect |
|--------------------------------|-------------|--------------------------------------------------------------------------------|
| WP_READ_ONLY | false | Blocks all write operations |
| WP_DRAFT_ONLY | false | Restricts to draft and pending statuses only |
| WP_DISABLE_DELETE | false | Blocks all delete operations |
| WP_DISABLE_PLUGIN_MANAGEMENT | false | Blocks plugin activate/deactivate (list still allowed) |
| WP_REQUIRE_APPROVAL | false | Blocks direct publish. Forces draft → pending → publish workflow |
| WP_CONFIRM_DESTRUCTIVE | false | Requires token confirmation before delete operations |
| WP_MCP_SECRET | (ephemeral) | Signing secret for confirmation tokens. Unset = a random per-process secret is generated, so tokens stop being valid after a restart. Required when WP_CONFIRM_DESTRUCTIVE=true in HTTP mode |
| WP_VISUAL_STAGING | false | When true, direct edits to published pages are intercepted. AI must use staging workflow: wp_create_staging_draft → edit draft → wp_merge_staging_to_live |
| WP_VALIDATE_BLOCKS | false | When true, auto-validates Gutenberg block structure on wp_update_post/wp_update_page. Blocks update if errors found |
| WP_ALLOWED_TYPES | all | Restricts to specific post types (e.g., post,page) |
| WP_ALLOWED_STATUSES | all | Restricts to specific statuses (e.g., draft,pending) |
| WP_MAX_CALLS_PER_MINUTE | unlimited | Client-side rate limiting |
| WP_AUDIT_LOG | on | Structured JSON audit trail |
| WP_AUDIT_CHAIN | on | Adds seq, prev and hash to each audit entry. Keyed by WP_MCP_SECRET when it is set. Verify with npm run verify:audit |
| WP_COMPACT_JSON | true | Compact JSON output (~30% token reduction). false for debugging |
| WP_WRITE_DIFF | auto | Compare a resource before and after each write. auto = posts and pages, all = every single-resource endpoint, off = disabled. Costs one extra GET per write |
| WP_CHANGE_JOURNAL_DURABLE | auto | With the MCP Diagnostics companion installed, snapshots are also stored in WordPress and survive a restart. off skips the probe |
| WP_CHANGE_JOURNAL | 20 | How many changes to keep in memory for wp_list_changes. off disables retention entirely. Never written to disk, lost on restart. See Data Retention |
| WP_TOOL_ENFORCE_PROFILE | false | When true, a tool outside the active scope is refused instead of merely hidden. Off by default because the previous behaviour was documented |
| WP_TOOL_PROFILE | editorial | Named set of categories to expose: editorial · shop · site · maintenance · all. See Tool profiles |
| WP_TOOL_CATEGORIES | (none) | Comma-separated categories to expose. Takes precedence over WP_TOOL_PROFILE. Always includes core. Categories: content · revisions · media · taxonomy · engagement · users · seo · audit · schema · intelligence · editorial · fse · widgets · plugins · pluginlayer · workflow · links · woocommerce · security · performance · health |
| PAGESPEED_API_KEY | (none) | Google PageSpeed Insights API key. Optional — wp_audit_page_speed degrades gracefully |
| WPSCAN_API_KEY | (none) | WPScan vulnerability database API key. Optional — free at wpscan.com/register |
Previewing and verifying writes
Every tool that mutates something accepts dry_run. Nothing is sent: the server reports
the request it would have made and stops.
{ "dry_run": true, "status": "preview", "tool": "wp_update_post",
"would": { "method": "POST", "endpoint": "/posts/42", "body": { "title": "New title" } } }Interception lives in the API layer rather than in each tool, so it holds for writes
reached indirectly and for any tool added later. A dry run bypasses WP_READ_ONLY,
WP_DISABLE_DELETE and WP_DISABLE_PLUGIN_MANAGEMENT — nothing is sent, so those
controls have nothing to protect, and seeing what a read-only deployment would do is
what makes it auditable. Execution stops at the first write, so a tool performing several
writes shows only the first; wp_bulk_update and wp_run_workflow implement their own
fuller previews.
Writes that do run are compared against the resource as it was. WP_WRITE_DIFF=auto
(the default) covers posts and pages, at the cost of one extra GET per write:
{ "success": true,
"changes": { "resource": "/posts/42", "effective": true,
"fields": { "title": { "before": "Old", "after": "New" },
"content": { "lines_added": 3, "lines_removed": 1 } } } }The field that matters is effective. A write can succeed and change nothing — the value
sent was identical, WordPress rejected it silently, or a page builder masks it, which is
exactly the Elementor failure the 5.6 guard was built for. A handler cannot tell you that
about itself; the comparison can.
Resources
Reference material addressed by URI, so an agent does not spend a tool call rediscovering it at the start of every conversation.
| URI | What it holds |
|---|---|
| wp://site | Name, URL, timezone, and the account this server authenticates as |
| wp://post-types | Registered post types and REST bases — the valid post_type values |
| wp://taxonomies | Taxonomies, the types they apply to, their REST bases |
| wp://governance | Which controls are on, which tools are exposed, what happens to a write |
wp://governance answers "why was that blocked" with no round trip — it reads no network
and works even when the site is unreachable.
Only genuinely referential data belongs here. An audit is a computation, not a document:
wp_audit(check, post_id) takes arguments, a resource does not, so the audits stayed
tools.
Prompts
The four built-in workflows are also exposed as MCP prompts, so a person can pick one in their client instead of describing it. They are generated from the workflow definitions, which means a prompt cannot describe a sequence the server does not run.
| Prompt | Arguments | Steps |
|---|---|---|
| seo_audit_and_stage | post_id | content brief → heading audit → staging draft |
| site_health_report | — | health status → issues → environment info |
| content_publish_safe | post_id, content | validate blocks → publish |
| wc_product_audit | — | product SEO → stock alerts |
A prompt resolves to the same wp_run_workflow call an agent would make, with the
arguments filled in. Prompts are user-initiated: a model running on its own never invokes
one, and does not need to — the tool is there for it.
Undoing a write
Each recorded change carries a change_id. wp_list_changes shows what this session
changed and whether each one can be undone; wp_rollback_change writes the previous
values back.
{ "success": true, "rolled_back": "chg_3", "restored": ["title", "_yoast_wpseo_title"],
"undo_id": "chg_4" }A rollback is itself a write, so it lands in the journal as its own change — the undo can be undone. Rolling the same change back twice is refused: the snapshot no longer describes the resource.
Three things are declared unrollbackable when they are recorded, not when you try:
| Case | Why |
|---|---|
| The write changed nothing | There is nothing to put back |
| Permanent deletion (force=true) | The resource, its ID and its relations are gone |
| Previous state above 256 kB | Restoring a truncated payload would corrupt the resource |
The journal holds the last 20 changes in memory and loses them on restart — see
Data Retention. wp_restore_revision remains the separate, durable
path for WordPress's own revisions, which cover post content but never meta.
Destructive confirmation flow
When WP_CONFIRM_DESTRUCTIVE=true, wp_delete_post and wp_delete_revision return a stateless confirmation token on the first call instead of executing. Pass it back on a second call to confirm.
mcp_trash_42_1785250649_cf49af092d438e1bHMAC-SHA-256 over the post, action and timestamp, truncated to 64 bits, compared in constant time, valid for 60 seconds, never stored. Changed in 6.0 — the signature was 16 bits until then, which is a guardrail against an agent's mistake but not against a brute-force.
Tokens are signed with WP_MCP_SECRET. When it is not set the server generates a random secret at startup — tokens stay unforgeable, but they stop being valid after a restart and cannot be validated by a second instance. In stdio mode this only costs you pending tokens on restart, and the server logs a warning. In HTTP mode, where restarts and multiple instances are expected, the server refuses to start rather than offer a control it cannot honour.
WP_MCP_SECRET=$(openssl rand -hex 32)This is a guardrail against accidental deletion by the agent, not an authorisation mechanism — see Safety Model.
Governance priority order: WP_READ_ONLY → WP_DISABLE_DELETE → WP_CONFIRM_DESTRUCTIVE
Deployment profiles
Agency content production — writers can create and edit, but never publish or delete:
WP_DRAFT_ONLY=true
WP_DISABLE_DELETE=true
WP_ALLOWED_STATUSES=draft,pending
WP_MAX_CALLS_PER_MINUTE=30Editorial review workflow — forces human approval before publication:
WP_REQUIRE_APPROVAL=true
WP_DISABLE_DELETE=true
WP_AUDIT_LOG=onCompliance monitoring — read-only access for auditing existing content:
WP_READ_ONLY=true
WP_AUDIT_LOG=onRegulated publishing — restrict to specific content types in a controlled environment:
WP_ALLOWED_TYPES=post
WP_ALLOWED_STATUSES=draft,pending,publish
WP_DISABLE_DELETE=true
WP_AUDIT_LOG=onLocked infrastructure — content operations allowed, but no plugin/theme changes:
WP_DISABLE_PLUGIN_MANAGEMENT=true
WP_DISABLE_DELETE=trueE-commerce safe mode — WooCommerce read and intelligence, no writes:
WP_READ_ONLY=true
WC_CONSUMER_KEY=ck_xxx
WC_CONSUMER_SECRET=cs_xxxLocked down — nothing gets deleted:
WP_DISABLE_DELETE=true
WP_DISABLE_PLUGIN_MANAGEMENT=true
WP_REQUIRE_APPROVAL=true
WP_TOOL_ENFORCE_PROFILE=true # the profile refuses, it does not merely hide
WP_VISUAL_STAGING=true
WP_VALIDATE_BLOCKS=true
WP_WRITE_DIFF=all
WP_CHANGE_JOURNAL=50
WP_MAX_CALLS_PER_MINUTE=30Deletion allowed, but never by accident — the same, with deletion re-enabled behind a signed confirmation:
WP_DISABLE_DELETE=false
WP_CONFIRM_DESTRUCTIVE=true
WP_MCP_SECRET=<a stable secret> # or tokens stop working after a restartThe two are separate on purpose. The priority order is WP_READ_ONLY →
WP_DISABLE_DELETE → WP_CONFIRM_DESTRUCTIVE, so turning on both WP_DISABLE_DELETE and
WP_CONFIRM_DESTRUCTIVE is not stricter than the first alone — the confirmation is simply
never reached.
None of this replaces a narrowly scoped WordPress account — see Safety Model.
Tool profiles
A profile decides which categories reach ListTools. editorial is the default: it covers
an article from brief to published and optimised, and leaves out the surface an editorial
agent has no business touching — user management, plugin activation, file permissions,
Full Site Editing, WooCommerce.
That is a reduction of surface first and of context second — but be precise about what kind of reduction.
By default a profile shapes ListTools, not the router. A tool the profile withholds is invisible to the model, so it will not be chosen by accident — and accident is the dominant risk. It is not refused: a client that already knows the name can still call it. Until 6.0 this page claimed the withholding was the stronger guarantee, which was true of mistakes and false of anyone deliberate.
Set WP_TOOL_ENFORCE_PROFILE=true and the profile becomes a refusal:
Blocked: "wp_delete_user" is outside the active tool scope (profile "editorial"),
and WP_TOOL_ENFORCE_PROFILE=true. Widen the scope to allow it.It stays opt-in because the previous behaviour was documented and someone may rely on it.
Turn it on for anything shared or remote. The names retired in 6.0 resolve to their
replacement first, so wp_audit_seo is allowed exactly when wp_audit is in scope —
enforcement does not quietly cancel the compatibility promise.
Even enforced, this is a control inside the MCP process, not a WordPress permission: an operator who can restart the server can restart it without the flag. See Safety Model.
Two columns, because a profile alone does not decide how many tools you see. Out of the
box is what a fresh install shows. Fully enabled adds the three conditional groups —
WC_CONSUMER_KEY, WP_REQUIRE_APPROVAL, WP_ENABLE_PLUGIN_INTELLIGENCE — each of which
gates its own tools regardless of profile.
| Profile | Categories | Out of the box | Fully enabled |
|---|---|---|---|
| editorial (default) | content · revisions · seo · audit · schema · intelligence · editorial · media · taxonomy · links · engagement · workflow · pluginlayer | 68 · ~8.9k | 77 · ~9.9k |
| shop | editorial + woocommerce | 68 · ~8.9k | 97 · ~12.0k |
| site | content · revisions · media · taxonomy · fse · widgets · plugins · pluginlayer | 40 · ~5.2k | 40 · ~5.2k |
| maintenance | health · performance · security · plugins · users | 40 · ~4.0k | 40 · ~4.0k |
| all | everything | 108 · ~13.1k | 137 · ~16.2k |
core is always exposed on top of the selected categories. shop shows the same 68 tools
as editorial until WooCommerce credentials are configured — the profile admits the
category, the credentials release the tools. site and maintenance contain none of the
conditional groups, so their two columns are identical.
# Default — no configuration needed
# WP_TOOL_PROFILE=editorial
# Everything, as before profiles existed
WP_TOOL_PROFILE=all
# Or pick categories directly — this always wins over WP_TOOL_PROFILE
WP_TOOL_CATEGORIES=seo,content,schemaA tool left out of the profile stays callable by default. Profiles shape what is
advertised in ListTools, not what the server executes — nothing you scripted against stops
working. Set WP_TOOL_ENFORCE_PROFILE=true to make the profile refuse instead.
Existing deployments are unaffected. WP_TOOL_CATEGORIES takes precedence over
WP_TOOL_PROFILE, so a configuration written before profiles existed keeps its exact
behaviour. Only deployments that set neither move from the full catalogue to editorial.
The active profile and the exposed count are logged at startup and reported by
wp_site_info.
Blocked actions return a clear error message explaining which control prevented execution, and are logged in the audit trail with status blocked.
MU-Plugin Companion
Some tools require the optional MCP Diagnostics companion mu-plugin to access data not available via the WordPress REST API.
Installation
cp companion/mcp-diagnostics.php /path/to/wp-content/mu-plugins/Exposed endpoints
Diagnostics — require manage_options
| Endpoint | Method | Description |
|---------------------------------------------|--------|------------------------------------------|
| /mcp-diagnostics/v1/debug-log | GET | Last N lines of debug.log by level |
| /mcp-diagnostics/v1/cron-events | GET | All scheduled WP-Cron events |
| /mcp-diagnostics/v1/transients | GET | Database transients with expiration/size |
| /mcp-diagnostics/v1/hooks | GET | Registered actions and filters |
Security — require manage_options
| Endpoint | Method | Description |
|---------------------------------------------|--------|------------------------------------------|
| /mcp-diagnostics/v1/user-activity | GET | Admin last login timestamps |
| /mcp-diagnostics/v1/file-permissions | GET | Critical file permission checks |
| /mcp-diagnostics/v1/modified-files | GET | Recently modified file listing |
Performance — requires manage_options
| Endpoint | Method | Description |
|---------------------------------------------|--------|------------------------------------------|
| /mcp-diagnostics/v1/database-bloat | GET | Database bloat analysis |
WooCommerce — requires manage_options
| Endpoint | Method | Description |
|---------------------------------------------|--------|------------------------------------------|
| /mcp-diagnostics/v1/wc-abandoned-carts | GET | Abandoned cart data from available sources|
Schema — requires edit_posts
| Endpoint | Method | Description |
|---------------------------------------------|--------|------------------------------------------|
| /mcp-diagnostics/v1/schema/{post_id} | GET | Read _custom_schema_jsonld meta |
| /mcp-diagnostics/v1/schema/{post_id} | POST | Write schema meta. Blocked by WP_READ_ONLY |
| /mcp-diagnostics/v1/schema/{post_id} | DELETE | Remove schema meta. Blocked by WP_READ_ONLY |
Polylang Free — public (no auth required)
| Endpoint | Method | Description |
|------------------------------------------------------|--------|----------------------------------|
| /mcp-diagnostics/v1/polylang/languages | GET | Polylang languages list |
| /mcp-diagnostics/v1/polylang/translations/{post_id}| GET | Post translations by language |
Users — requires manage_options
| Endpoint | Method | Description |
|---------------------------------------------|--------|------------------------------------------|
| /mcp-diagnostics/v1/password-reset | POST | Trigger password reset email |
Diagnostics endpoints require manage_options (Administrator). The change journal below requires edit_others_posts instead — restoring a snapshot rewrites content, so it is g
