@adsim/wordpress-mcp-server 3.1.0 → 4.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.md +564 -176
  2. package/dxt/manifest.json +93 -9
  3. package/index.js +3624 -36
  4. package/package.json +1 -1
  5. package/src/confirmationToken.js +64 -0
  6. package/src/contentAnalyzer.js +476 -0
  7. package/src/htmlParser.js +80 -0
  8. package/src/linkUtils.js +158 -0
  9. package/src/pluginDetector.js +158 -0
  10. package/src/utils/contentCompressor.js +116 -0
  11. package/src/woocommerceClient.js +88 -0
  12. package/tests/unit/contentAnalyzer.test.js +397 -0
  13. package/tests/unit/pluginDetector.test.js +167 -0
  14. package/tests/unit/tools/analyzeEeatSignals.test.js +192 -0
  15. package/tests/unit/tools/approval.test.js +251 -0
  16. package/tests/unit/tools/auditCanonicals.test.js +149 -0
  17. package/tests/unit/tools/auditHeadingStructure.test.js +150 -0
  18. package/tests/unit/tools/auditMediaSeo.test.js +123 -0
  19. package/tests/unit/tools/auditOutboundLinks.test.js +175 -0
  20. package/tests/unit/tools/auditTaxonomies.test.js +173 -0
  21. package/tests/unit/tools/contentCompressor.test.js +320 -0
  22. package/tests/unit/tools/contentIntelligence.test.js +2168 -0
  23. package/tests/unit/tools/destructive.test.js +246 -0
  24. package/tests/unit/tools/findBrokenInternalLinks.test.js +222 -0
  25. package/tests/unit/tools/findKeywordCannibalization.test.js +183 -0
  26. package/tests/unit/tools/findOrphanPages.test.js +145 -0
  27. package/tests/unit/tools/findThinContent.test.js +145 -0
  28. package/tests/unit/tools/internalLinks.test.js +283 -0
  29. package/tests/unit/tools/perTargetControls.test.js +228 -0
  30. package/tests/unit/tools/pluginIntelligence.test.js +864 -0
  31. package/tests/unit/tools/site.test.js +6 -1
  32. package/tests/unit/tools/woocommerce.test.js +344 -0
  33. package/tests/unit/tools/woocommerceIntelligence.test.js +341 -0
  34. package/tests/unit/tools/woocommerceWrite.test.js +323 -0
package/README.md CHANGED
@@ -1,33 +1,35 @@
1
1
  # WordPress MCP Server
2
2
 
3
3
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
- [![Node.js](https://img.shields.io/badge/Node.js-18%2B-green)](https://nodejs.org/)
5
- [![MCP SDK](https://img.shields.io/badge/MCP_SDK-1.8%2B-blue)](https://modelcontextprotocol.io/)
6
- [![Tests](https://img.shields.io/badge/Tests-171%20passed-brightgreen)]()
4
+ [![Node.js](https://img.shields.io/badge/Node.js-%3E%3D18-green.svg)](https://nodejs.org/)
5
+ [![MCP SDK](https://img.shields.io/badge/MCP-SDK-blue.svg)](https://github.com/anthropics/mcp)
6
+ [![Tests](https://img.shields.io/badge/tests-674%20passing-brightgreen.svg)](https://github.com/GeorgesAdSim/wordpress-mcp-server/actions)
7
+ [![npm](https://img.shields.io/npm/v/@adsim/wordpress-mcp-server.svg)](https://www.npmjs.com/package/@adsim/wordpress-mcp-server)
7
8
 
8
- Enterprise Governance · Audit Trail · Multi-Site · Plugin-Free
9
+ **Enterprise Governance · Audit Trail · Multi-Site · Plugin-Free**
9
10
 
10
11
  The enterprise governance layer for Claude-to-WordPress integrations — secure, auditable, and multi-site.
11
12
 
12
- **v2.2.0 Enterprise · 35 tools · 171 Vitest tests · GitHub Actions CI · SEO metadata · Plugin & theme management · Revision control · Execution controls · JSON audit trail · Multi-site targeting**
13
+ **v4.5.0 Enterprise** · 85 tools · 674 Vitest tests · GitHub Actions CI · HTTP Streamable transport · MCPB bundle · SEO metadata · SEO audit suite · Content intelligence · Plugin intelligence · Plugin & theme management · Revision control · Editorial approval workflow · Destructive confirmation · Internal link analysis · WooCommerce (read + intelligence + write) · Execution controls · JSON audit trail · Multi-site targeting
13
14
 
14
15
  ---
15
16
 
16
17
  ## Architecture
17
-
18
18
  ```
19
19
  ┌─────────────────────────┐
20
20
  │ Claude Client │ Claude Desktop · Claude Code · Any MCP client
21
21
  └────────────┬────────────┘
22
- │ MCP Protocol (stdio)
22
+ │ MCP Protocol (stdio or HTTP Streamable)
23
23
  ┌────────────▼────────────┐
24
24
  │ WordPress MCP Server │ Node.js · Standalone · No WordPress plugin
25
25
  ├─────────────────────────┤
26
26
  │ Execution Controls │ Read-only · Draft-only · Plugin mgmt · Type/status allowlists
27
27
  ├─────────────────────────┤
28
- │ Audit Logging │ JSON on stderr · 35 instrumentation points
28
+ │ Audit Logging │ JSON on stderr · 79 instrumentation points
29
29
  ├─────────────────────────┤
30
30
  │ Rate Limiting │ Client-side · Configurable per-minute cap
31
+ ├─────────────────────────┤
32
+ │ HTTP Transport │ Bearer auth · Session management · Origin validation
31
33
  └────────────┬────────────┘
32
34
  │ HTTPS + WordPress Application Password (Basic Auth over TLS)
33
35
  ┌────────────▼────────────┐
@@ -37,7 +39,7 @@ The enterprise governance layer for Claude-to-WordPress integrations — secure,
37
39
 
38
40
  ## Why This Server
39
41
 
40
- 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.
42
+ 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.
41
43
 
42
44
  In regulated environments — financial services, healthcare, legal, government — AI-powered content operations need guardrails. This server provides them out of the box: read-only mode for monitoring, draft-only mode for review workflows, structured audit logs for compliance, and multi-site management for agencies operating across client portfolios.
43
45
 
@@ -56,7 +58,7 @@ This server is designed for safe operation in production environments:
56
58
 
57
59
  ## Data Retention
58
60
 
59
- The server does not store or persist WordPress content. All processing is stateless — content flows through the server and is never cached, written to disk, or retained in memory beyond the scope of a single tool invocation. Audit logs are emitted to stderr in real-time and can be disabled (WP_AUDIT_LOG=off) or redirected to any logging pipeline based on deployment requirements. Zero data retention by design.
61
+ The server does not store or persist WordPress content. All processing is stateless — content flows through the server and is never cached, written to disk, or retained in memory beyond the scope of a single tool invocation. Audit logs are emitted to stderr in real-time and can be disabled (`WP_AUDIT_LOG=off`) or redirected to any logging pipeline based on deployment requirements. Zero data retention by design.
60
62
 
61
63
  ---
62
64
 
@@ -68,9 +70,18 @@ The server does not store or persist WordPress content. All processing is statel
68
70
  - WordPress site with REST API enabled (default since WP 4.7)
69
71
  - WordPress Application Password (WP 5.6+)
70
72
  - HTTPS endpoint (required for production)
73
+ - WooCommerce 3.5+ (optional, for WooCommerce tools)
71
74
 
72
- ### Install
75
+ ### Install from npm (recommended)
76
+ ```bash
77
+ # Run directly — no install needed
78
+ npx -y @adsim/wordpress-mcp-server
79
+
80
+ # Or install globally
81
+ npm install -g @adsim/wordpress-mcp-server
82
+ ```
73
83
 
84
+ ### Install from GitHub
74
85
  ```bash
75
86
  git clone https://github.com/GeorgesAdSim/wordpress-mcp-server.git
76
87
  cd wordpress-mcp-server
@@ -80,11 +91,14 @@ npm install
80
91
  ### Configure
81
92
 
82
93
  Create a `.env` file:
83
-
84
- ```bash
94
+ ```env
85
95
  WP_API_URL=https://yoursite.com
86
96
  WP_API_USERNAME=your-username
87
97
  WP_API_PASSWORD=xxxx xxxx xxxx xxxx xxxx xxxx
98
+
99
+ # Optional: WooCommerce (generate at WooCommerce → Settings → Advanced → REST API)
100
+ WC_CONSUMER_KEY=ck_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
101
+ WC_CONSUMER_SECRET=cs_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
88
102
  ```
89
103
 
90
104
  To generate an Application Password: WordPress Admin → Users → Profile → Application Passwords → Add New.
@@ -93,15 +107,14 @@ To generate an Application Password: WordPress Admin → Users → Profile → A
93
107
 
94
108
  Add to `claude_desktop_config.json`:
95
109
 
96
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
97
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
98
-
110
+ - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
111
+ - Windows: `%APPDATA%\Claude\claude_desktop_config.json`
99
112
  ```json
100
113
  {
101
114
  "mcpServers": {
102
115
  "wordpress": {
103
- "command": "node",
104
- "args": ["/path/to/wordpress-mcp-server/index.js"],
116
+ "command": "npx",
117
+ "args": ["-y", "@adsim/wordpress-mcp-server"],
105
118
  "env": {
106
119
  "WP_API_URL": "https://yoursite.com",
107
120
  "WP_API_USERNAME": "your-username",
@@ -113,139 +126,319 @@ Add to `claude_desktop_config.json`:
113
126
  ```
114
127
 
115
128
  ### Connect to Claude Code
116
-
117
129
  ```bash
118
130
  claude mcp add wordpress \
119
131
  -e WP_API_URL=https://yoursite.com \
120
132
  -e WP_API_USERNAME=your-username \
121
133
  -e WP_API_PASSWORD="xxxx xxxx xxxx xxxx xxxx xxxx" \
122
- -- node /path/to/wordpress-mcp-server/index.js
134
+ -- npx -y @adsim/wordpress-mcp-server
135
+ ```
136
+
137
+ ---
138
+
139
+ ## HTTP Streamable Transport
140
+
141
+ > **New in v3.0.0** — Run the server over HTTP instead of (or alongside) stdio, following the MCP spec 2025-03-26.
142
+
143
+ ### Start in HTTP mode
144
+ ```bash
145
+ MCP_TRANSPORT=http \
146
+ MCP_HTTP_PORT=3000 \
147
+ MCP_AUTH_TOKEN=your-secret-token \
148
+ WP_API_URL=https://yoursite.com \
149
+ WP_API_USERNAME=your-username \
150
+ WP_API_PASSWORD="xxxx xxxx xxxx xxxx" \
151
+ npx -y @adsim/wordpress-mcp-server
152
+ ```
153
+
154
+ ### Dual mode (stdio + HTTP simultaneously)
155
+ ```bash
156
+ MCP_TRANSPORT=http \
157
+ MCP_DUAL_MODE=true \
158
+ MCP_AUTH_TOKEN=your-secret-token \
159
+ npx -y @adsim/wordpress-mcp-server
160
+ ```
161
+
162
+ ### HTTP environment variables
163
+
164
+ | Variable | Default | Description |
165
+ |---|---|---|
166
+ | `MCP_TRANSPORT` | `stdio` | Set to `http` to enable HTTP Streamable transport |
167
+ | `MCP_HTTP_PORT` | `3000` | HTTP server port |
168
+ | `MCP_HTTP_HOST` | `127.0.0.1` | Bind address |
169
+ | `MCP_AUTH_TOKEN` | _(none)_ | Bearer token for authentication (required in HTTP mode) |
170
+ | `MCP_ALLOWED_ORIGINS` | _(none)_ | Comma-separated allowed origins (anti-DNS-rebinding) |
171
+ | `MCP_SESSION_TIMEOUT_MS` | `3600000` | Session TTL in milliseconds (1 hour) |
172
+ | `MCP_DUAL_MODE` | `false` | Run stdio and HTTP transports simultaneously |
173
+
174
+ ### Health check
175
+ ```bash
176
+ curl http://localhost:3000/health
177
+ # → { "status": "ok", "version": "4.4.0", "transport": "http" }
178
+ ```
179
+
180
+ ### Connect an MCP client via HTTP
181
+ ```json
182
+ {
183
+ "mcpServers": {
184
+ "wordpress-http": {
185
+ "url": "http://localhost:3000/mcp",
186
+ "headers": {
187
+ "Authorization": "Bearer your-secret-token"
188
+ }
189
+ }
190
+ }
191
+ }
123
192
  ```
124
193
 
125
194
  ---
126
195
 
127
- ## Available Tools (35)
196
+ ## MCPB Bundle — Claude Desktop One-Click Install
197
+
198
+ > **New in v3.1.0** — Package the server as a `.mcpb` bundle for Claude Desktop distribution.
199
+
200
+ The bundle stores WordPress credentials securely in the OS keychain (`sensitive: true`) — no manual JSON editing required.
201
+
202
+ ### Build the bundle
203
+ ```bash
204
+ npm run build:mcpb
205
+ # → wordpress-mcp-server.mcpb
206
+ ```
207
+
208
+ ### Install in Claude Desktop
209
+
210
+ Double-click `wordpress-mcp-server.mcpb` — Claude Desktop will prompt for:
211
+ - WordPress Site URL
212
+ - WordPress Username
213
+ - WordPress Application Password _(stored in OS keychain)_
214
+
215
+ ---
216
+
217
+ ## Available Tools (79)
128
218
 
129
219
  ### Content Management
130
220
 
131
221
  | Tool | Description |
132
- |------|-------------|
133
- | wp_list_posts | List posts with pagination, filtering by status/category/tag/author, and search |
134
- | wp_get_post | Get a post by ID with full content, meta fields, and taxonomy info |
135
- | wp_create_post | Create a post (defaults to draft). Supports HTML, categories, tags, featured image, meta |
136
- | wp_update_post | Update any post field. Only provided fields are modified |
137
- | wp_delete_post | Move to trash by default. Permanent deletion requires force=true |
138
- | wp_search | Full-text search across all content types |
139
- | wp_list_pages | List pages with hierarchy (parent/child), templates, and menu order |
140
- | wp_get_page | Get page content, template, and hierarchy info |
141
- | wp_create_page | Create a page with parent, template, and menu_order support |
142
- | wp_update_page | Update any page field |
222
+ |---|---|
223
+ | `wp_list_posts` | List posts with pagination, filtering by status/category/tag/author, and search |
224
+ | `wp_get_post` | Get a post by ID with full content, meta fields, and taxonomy info |
225
+ | `wp_create_post` | Create a post (defaults to draft). Supports HTML, categories, tags, featured image, meta |
226
+ | `wp_update_post` | Update any post field. Only provided fields are modified |
227
+ | `wp_delete_post` | Move to trash by default. Permanent deletion requires `force=true`. Returns confirmation token when `WP_CONFIRM_DESTRUCTIVE=true` |
228
+ | `wp_search` | Full-text search across all content types |
229
+ | `wp_list_pages` | List pages with hierarchy (parent/child), templates, and menu order |
230
+ | `wp_get_page` | Get page content, template, and hierarchy info |
231
+ | `wp_create_page` | Create a page with parent, template, and menu_order support |
232
+ | `wp_update_page` | Update any page field |
143
233
 
144
234
  ### Media Library
145
235
 
146
236
  | Tool | Description |
147
- |------|-------------|
148
- | wp_list_media | Browse media with type filtering (image/video/audio/document) |
149
- | wp_get_media | Get URL, dimensions, alt text, caption, and all available sizes |
150
- | wp_upload_media | Upload a file from a public URL to the WordPress media library |
237
+ |---|---|
238
+ | `wp_list_media` | Browse media with type filtering (image/video/audio/document) |
239
+ | `wp_get_media` | Get URL, dimensions, alt text, caption, and all available sizes |
240
+ | `wp_upload_media` | Upload a file from a public URL to the WordPress media library |
151
241
 
152
242
  ### Taxonomies & Structure
153
243
 
154
244
  | Tool | Description |
155
- |------|-------------|
156
- | wp_list_categories | List categories with hierarchy, post count, and descriptions |
157
- | wp_list_tags | List tags with post count |
158
- | wp_create_taxonomy_term | Create a new category or tag |
159
- | wp_list_post_types | Discover all registered post types (including custom ones) |
160
- | wp_list_custom_posts | List content from any custom post type (products, portfolio, events) |
245
+ |---|---|
246
+ | `wp_list_categories` | List categories with hierarchy, post count, and descriptions |
247
+ | `wp_list_tags` | List tags with post count |
248
+ | `wp_create_taxonomy_term` | Create a new category or tag |
249
+ | `wp_list_post_types` | Discover all registered post types (including custom ones) |
250
+ | `wp_list_custom_posts` | List content from any custom post type (products, portfolio, events) |
161
251
 
162
252
  ### Engagement
163
253
 
164
254
  | Tool | Description |
165
- |------|-------------|
166
- | wp_list_comments | List comments with filtering by post, status, and author |
167
- | wp_create_comment | Create a comment or reply on any post |
168
- | wp_list_users | List users with roles (read-only) |
255
+ |---|---|
256
+ | `wp_list_comments` | List comments with filtering by post, status, and author |
257
+ | `wp_create_comment` | Create a comment or reply on any post |
258
+ | `wp_list_users` | List users with roles (read-only) |
169
259
 
170
260
  ### SEO Metadata
171
261
 
172
262
  | Tool | Description |
173
- |------|-------------|
174
- | wp_get_seo_meta | Read SEO title, description, focus keyword, canonical, robots, Open Graph. Auto-detects Yoast, RankMath, SEOPress, All in One SEO |
175
- | wp_update_seo_meta | Update SEO metadata with automatic plugin detection |
176
- | wp_audit_seo | Bulk audit SEO across posts/pages with quality scoring (0-100), missing fields detection, and length checks |
263
+ |---|---|
264
+ | `wp_get_seo_meta` | Read SEO title, description, focus keyword, canonical, robots, Open Graph. Auto-detects Yoast, RankMath, SEOPress, All in One SEO |
265
+ | `wp_update_seo_meta` | Update SEO metadata with automatic plugin detection |
266
+ | `wp_audit_seo` | Bulk audit SEO across posts/pages with quality scoring (0-100), missing fields detection, and length checks |
177
267
 
178
268
  SEO metadata updates are subject to the same enterprise controls and execution policies as all other write operations.
179
269
 
270
+ ### SEO Audit Suite
271
+
272
+ > **New in v4.0–v4.2** — Deep technical SEO analysis without requiring any WordPress plugin.
273
+
274
+ | Tool | Description |
275
+ |---|---|
276
+ | `wp_audit_media_seo` | Audit media library for missing alt text, short alt text, and unoptimized filenames. Returns per-image scores and prioritized fix list |
277
+ | `wp_find_orphan_pages` | Identify posts with no internal links pointing to them, sorted by word count. Configurable minimum word threshold and exclusion list |
278
+ | `wp_audit_heading_structure` | Analyze H1/H2/H3 hierarchy in post content. Detects H1 in body, heading level skips, empty headings, focus keyword absent from H2 |
279
+ | `wp_find_thin_content` | Surface posts below a configurable word count threshold. Scores content quality by word count, heading density, and paragraph structure |
280
+ | `wp_audit_canonicals` | Validate canonical URLs across posts and pages. Detects missing canonicals, self-referencing mismatches, and cross-domain canonicals. Auto-detects RankMath/Yoast/SEOPress/AIOSEO |
281
+ | `wp_analyze_eeat_signals` | Score E-E-A-T signals per post: author bio presence, publication/update dates, outbound citations, word count, structured data markers. Returns a 0-100 score with a breakdown by dimension |
282
+ | `wp_find_broken_internal_links` | Check all internal links in a post via HEAD requests. Returns broken (4xx/5xx), redirected (3xx), and slow links. Configurable batch size and timeout |
283
+ | `wp_find_keyword_cannibalization` | Detect posts sharing the same RankMath/Yoast/SEOPress/AIOSEO focus keyword. Groups conflicts by keyword and flags the weakest post by word count |
284
+ | `wp_audit_taxonomies` | Identify taxonomy bloat: unused categories/tags, near-duplicate terms via Levenshtein distance, single-post terms, and over-tagged posts |
285
+ | `wp_audit_outbound_links` | Analyze external link profile per post. Detects links to low-authority domains, missing rel="nofollow" on sponsored links, and broken external URLs |
286
+
287
+ All SEO audit tools are read-only and always allowed regardless of governance flags.
288
+
289
+ ### Content Intelligence
290
+
291
+ > **New in v4.4.0** — Deep content analysis and editorial intelligence without any WordPress plugin.
292
+
293
+ | Tool | Description |
294
+ |---|---|
295
+ | `wp_get_content_brief` | Editorial brief aggregator: SEO + structure + links in 1 call |
296
+ | `wp_extract_post_outline` | H1-H6 outline extraction with category-level pattern analysis |
297
+ | `wp_audit_readability` | Bulk Flesch-Kincaid FR scoring with transition word and passive voice analysis |
298
+ | `wp_audit_update_frequency` | Outdated content detection cross-referenced with SEO scores |
299
+ | `wp_build_link_map` | Internal link matrix with simplified PageRank scoring (0-100) |
300
+ | `wp_audit_anchor_texts` | Anchor text diversity audit: generic, over-optimized, image link detection |
301
+ | `wp_audit_schema_markup` | JSON-LD schema.org detection and validation (Article, FAQ, HowTo, LocalBusiness) |
302
+ | `wp_audit_content_structure` | Editorial structure scoring (0-100): intro, conclusion, FAQ, TOC, lists, images |
303
+ | `wp_find_duplicate_content` | TF-IDF cosine similarity for near-duplicate detection with union-find clustering |
304
+ | `wp_find_content_gaps` | Taxonomy under-representation analysis (categories + tags) |
305
+ | `wp_extract_faq_blocks` | FAQ inventory: JSON-LD, Gutenberg blocks, HTML patterns |
306
+ | `wp_audit_cta_presence` | CTA detection (6 types) with scoring 0-100 |
307
+ | `wp_extract_entities` | Regex/heuristic named entity extraction (brands, locations, persons, organizations) |
308
+ | `wp_get_publishing_velocity` | Publication cadence by author/category with trend detection |
309
+ | `wp_compare_revisions_diff` | Textual diff between revisions with amplitude scoring |
310
+ | `wp_list_posts_by_word_count` | Posts sorted by length with 6-tier segmentation |
311
+
312
+ All Content Intelligence tools are read-only and always allowed regardless of governance flags.
313
+
180
314
  ### Plugins
181
315
 
182
316
  | Tool | Description |
183
- |------|-------------|
184
- | wp_list_plugins | List installed plugins with status, version, author. Requires Administrator (activate_plugins capability) |
185
- | wp_activate_plugin | Activate a plugin. Blocked by `WP_READ_ONLY` and `WP_DISABLE_PLUGIN_MANAGEMENT` |
186
- | wp_deactivate_plugin | Deactivate a plugin. Blocked by `WP_READ_ONLY` and `WP_DISABLE_PLUGIN_MANAGEMENT` |
317
+ |---|---|
318
+ | `wp_list_plugins` | List installed plugins with status, version, author. Requires Administrator (`activate_plugins` capability) |
319
+ | `wp_activate_plugin` | Activate a plugin. Blocked by `WP_READ_ONLY` and `WP_DISABLE_PLUGIN_MANAGEMENT` |
320
+ | `wp_deactivate_plugin` | Deactivate a plugin. Blocked by `WP_READ_ONLY` and `WP_DISABLE_PLUGIN_MANAGEMENT` |
187
321
 
188
322
  ### Themes
189
323
 
190
324
  | Tool | Description |
191
- |------|-------------|
192
- | wp_list_themes | List installed themes with active theme detection. Requires `switch_themes` capability |
193
- | wp_get_theme | Get theme details by stylesheet slug |
325
+ |---|---|
326
+ | `wp_list_themes` | List installed themes with active theme detection. Requires `switch_themes` capability |
327
+ | `wp_get_theme` | Get theme details by stylesheet slug |
194
328
 
195
329
  ### Revisions
196
330
 
197
331
  | Tool | Description |
198
- |------|-------------|
199
- | wp_list_revisions | List revisions of a post or page (metadata only) |
200
- | wp_get_revision | Get a specific revision with full content |
201
- | wp_restore_revision | Restore a post to a previous revision (plugin-free 2-step approach) |
202
- | wp_delete_revision | Permanently delete a revision. Blocked by `WP_READ_ONLY` and `WP_DISABLE_DELETE` |
332
+ |---|---|
333
+ | `wp_list_revisions` | List revisions of a post or page (metadata only) |
334
+ | `wp_get_revision` | Get a specific revision with full content |
335
+ | `wp_restore_revision` | Restore a post to a previous revision (plugin-free 2-step approach) |
336
+ | `wp_delete_revision` | Permanently delete a revision. Blocked by `WP_READ_ONLY`, `WP_DISABLE_DELETE`, and `WP_CONFIRM_DESTRUCTIVE` |
337
+
338
+ ### Editorial Workflow
339
+
340
+ > **New in v3.2.0** — Approval workflow for regulated content operations.
341
+
342
+ | Tool | Description |
343
+ |---|---|
344
+ | `wp_submit_for_review` | Transition a draft post to pending status (author action). Blocked by `WP_READ_ONLY` |
345
+ | `wp_approve_post` | Transition a pending post to publish (editor/admin action). Blocked by `WP_READ_ONLY` and `WP_DRAFT_ONLY` |
346
+ | `wp_reject_post` | Return a pending post to draft with a mandatory rejection reason (editor/admin action). Blocked by `WP_READ_ONLY` |
347
+
348
+ The approval workflow is enforced by `WP_REQUIRE_APPROVAL=true`, which blocks direct publish via `wp_update_post` and forces the draft → pending → publish path.
349
+
350
+ ### Internal Link Intelligence
351
+
352
+ > **New in v3.3.0** — Audit and improve internal linking without auto-insertion.
353
+
354
+ | Tool | Description |
355
+ |---|---|
356
+ | `wp_analyze_links` | Audit all internal and external links in a post. HEAD request verification per link (broken/warning/unknown). Configurable max checks and timeout |
357
+ | `wp_suggest_internal_links` | Semantic link suggestions scored by category match (+3), freshness (+3/2/1), SEO focus keyword match (+2), title match (+2). Excludes already-linked posts |
358
+
359
+ Pre-flight linking workflow: `wp_suggest_internal_links` → user validates → `wp_update_post` (never auto-insert).
360
+
361
+ ### WooCommerce
362
+
363
+ > **New in v3.4.0–v3.6.0** — Full WooCommerce integration with read, intelligence, and write operations.
364
+
365
+ Requires `WC_CONSUMER_KEY` and `WC_CONSUMER_SECRET` environment variables. Generate API keys at WooCommerce → Settings → Advanced → REST API.
366
+
367
+ | Tool | Description |
368
+ |---|---|
369
+ | `wc_list_products` | List products with filtering by status, category, search, and sorting by price/popularity |
370
+ | `wc_get_product` | Get a product by ID with full details. Includes variations summary for variable products |
371
+ | `wc_list_orders` | List orders with filtering by status, customer, and date |
372
+ | `wc_get_order` | Get an order by ID with line items, shipping, billing, and payment details |
373
+ | `wc_list_customers` | List customers with search and role filtering |
374
+ | `wc_get_customer` | Get a customer by ID with full profile, order history summary, and lifetime value |
375
+ | `wc_list_coupons` | List coupons with filtering by type, expiry status, and usage |
376
+ | `wc_get_coupon` | Get a coupon by ID with full discount rules and usage statistics |
377
+ | `wc_sales_report` | Generate sales summary for a date range: revenue, orders, average order value, top products |
378
+ | `wc_top_products` | Rank products by revenue, quantity sold, or order count for a given period |
379
+ | `wc_price_guardrail` | Analyze a price change for safety (read-only). Returns safe/unsafe based on configurable threshold percentage |
380
+ | `wc_update_product` | Update product fields (title, description, price, stock, status). Blocked by `WP_READ_ONLY` and subject to `wc_price_guardrail` thresholds |
381
+ | `wc_update_order_status` | Transition order status (e.g., processing → completed). Blocked by `WP_READ_ONLY` |
382
+
383
+ All WooCommerce write tools are blocked by `WP_READ_ONLY`. `wc_price_guardrail` is always allowed — it never modifies data.
203
384
 
204
385
  ### Operations
205
386
 
206
387
  | Tool | Description |
207
- |------|-------------|
208
- | wp_set_target | Switch active WordPress site in multi-target mode |
209
- | wp_site_info | Site info, current user, post types, enterprise controls, and available targets |
388
+ |---|---|
389
+ | `wp_set_target` | Switch active WordPress site in multi-target mode |
390
+ | `wp_site_info` | Site info, current user, post types, enterprise controls, and available targets |
210
391
 
211
392
  ---
212
393
 
213
394
  ## Enterprise Controls
214
395
 
215
- Configure execution policy via environment variables. All restrictions are enforced before any API call is made — including SEO metadata and plugin operations.
396
+ Configure execution policy via environment variables. All restrictions are enforced before any API call is made — including SEO metadata, plugin operations, and WooCommerce writes.
216
397
 
217
398
  | Control | Default | Effect |
218
- |---------|---------|--------|
219
- | WP_READ_ONLY | false | Blocks all write operations (create, update, delete, upload, SEO updates, plugin management) |
220
- | WP_DRAFT_ONLY | false | Restricts to draft and pending statuses only |
221
- | WP_DISABLE_DELETE | false | Blocks all delete operations (posts + revisions) |
222
- | WP_DISABLE_PLUGIN_MANAGEMENT | false | Blocks plugin activate/deactivate (list still allowed) |
223
- | WP_ALLOWED_TYPES | all | Restricts to specific post types (e.g., post,page) |
224
- | WP_ALLOWED_STATUSES | all | Restricts to specific statuses (e.g., draft,pending) |
225
- | WP_MAX_CALLS_PER_MINUTE | unlimited | Client-side rate limiting |
226
- | WP_AUDIT_LOG | on | Structured JSON audit trail |
399
+ |---|---|---|
400
+ | `WP_READ_ONLY` | `false` | Blocks all write operations (create, update, delete, upload, SEO updates, plugin management, WooCommerce writes) |
401
+ | `WP_DRAFT_ONLY` | `false` | Restricts to draft and pending statuses only |
402
+ | `WP_DISABLE_DELETE` | `false` | Blocks all delete operations (posts + revisions) |
403
+ | `WP_DISABLE_PLUGIN_MANAGEMENT` | `false` | Blocks plugin activate/deactivate (list still allowed) |
404
+ | `WP_REQUIRE_APPROVAL` | `false` | Blocks direct publish via `wp_update_post`. Forces draft → pending → publish approval workflow |
405
+ | `WP_CONFIRM_DESTRUCTIVE` | `false` | Requires a token confirmation before `wp_delete_post` and `wp_delete_revision` execute |
406
+ | `WP_ALLOWED_TYPES` | `all` | Restricts to specific post types (e.g., `post,page`) |
407
+ | `WP_ALLOWED_STATUSES` | `all` | Restricts to specific statuses (e.g., `draft,pending`) |
408
+ | `WP_MAX_CALLS_PER_MINUTE` | unlimited | Client-side rate limiting |
409
+ | `WP_AUDIT_LOG` | `on` | Structured JSON audit trail |
410
+
411
+ ### Destructive confirmation flow
412
+
413
+ When `WP_CONFIRM_DESTRUCTIVE=true`, `wp_delete_post` and `wp_delete_revision` return a stateless confirmation token on the first call instead of executing. The token is valid for 60 seconds (SHA-256, zero persistence). Pass the token back on a second call to confirm execution.
414
+
415
+ Governance priority order: `WP_READ_ONLY` → `WP_DISABLE_DELETE` → `WP_CONFIRM_DESTRUCTIVE`
227
416
 
228
417
  ### Deployment profiles
229
418
 
230
419
  **Agency content production** — writers can create and edit, but never publish or delete:
231
-
232
- ```bash
420
+ ```env
233
421
  WP_DRAFT_ONLY=true
234
422
  WP_DISABLE_DELETE=true
235
423
  WP_ALLOWED_STATUSES=draft,pending
236
424
  WP_MAX_CALLS_PER_MINUTE=30
237
425
  ```
238
426
 
239
- **Compliance monitoring** — read-only access for auditing existing content:
427
+ **Editorial review workflow** — forces human approval before publication:
428
+ ```env
429
+ WP_REQUIRE_APPROVAL=true
430
+ WP_DISABLE_DELETE=true
431
+ WP_AUDIT_LOG=on
432
+ ```
240
433
 
241
- ```bash
434
+ **Compliance monitoring** — read-only access for auditing existing content:
435
+ ```env
242
436
  WP_READ_ONLY=true
243
437
  WP_AUDIT_LOG=on
244
438
  ```
245
439
 
246
440
  **Regulated publishing** — restrict to specific content types in a controlled environment:
247
-
248
- ```bash
441
+ ```env
249
442
  WP_ALLOWED_TYPES=post
250
443
  WP_ALLOWED_STATUSES=draft,pending,publish
251
444
  WP_DISABLE_DELETE=true
@@ -253,12 +446,18 @@ WP_AUDIT_LOG=on
253
446
  ```
254
447
 
255
448
  **Locked infrastructure** — content operations allowed, but no plugin/theme changes:
256
-
257
- ```bash
449
+ ```env
258
450
  WP_DISABLE_PLUGIN_MANAGEMENT=true
259
451
  WP_DISABLE_DELETE=true
260
452
  ```
261
453
 
454
+ **E-commerce safe mode** — WooCommerce read and intelligence, no writes:
455
+ ```env
456
+ WP_READ_ONLY=true
457
+ WC_CONSUMER_KEY=ck_xxx
458
+ WC_CONSUMER_SECRET=cs_xxx
459
+ ```
460
+
262
461
  Blocked actions return a clear error message explaining which control prevented execution, and are logged in the audit trail with status `blocked`.
263
462
 
264
463
  ---
@@ -269,17 +468,17 @@ The SEO tools auto-detect which SEO plugin is installed on your WordPress site a
269
468
 
270
469
  Supported plugins:
271
470
 
272
- - **Yoast SEO** — _yoast_wpseo_title, _yoast_wpseo_metadesc, _yoast_wpseo_focuskw, plus yoast_head_json REST API extension
273
- - **RankMath** — rank_math_title, rank_math_description, rank_math_focus_keyword
274
- - **SEOPress** — _seopress_titles_title, _seopress_titles_desc, _seopress_analysis_target_kw
275
- - **All in One SEO** — _aioseo_title, _aioseo_description, _aioseo_keywords
471
+ - **Yoast SEO** — `_yoast_wpseo_title`, `_yoast_wpseo_metadesc`, `_yoast_wpseo_focuskw`, plus `yoast_head_json` REST API extension
472
+ - **RankMath** — `rank_math_title`, `rank_math_description`, `rank_math_focus_keyword`
473
+ - **SEOPress** — `_seopress_titles_title`, `_seopress_titles_desc`, `_seopress_analysis_target_kw`
474
+ - **All in One SEO** — `_aioseo_title`, `_aioseo_description`, `_aioseo_keywords`
276
475
 
277
476
  ### SEO Audit Scoring
278
477
 
279
478
  `wp_audit_seo` scores each post on a 100-point scale:
280
479
 
281
480
  | Check | Penalty |
282
- |-------|---------|
481
+ |---|---|
283
482
  | Missing SEO title | -30 |
284
483
  | SEO title too short (< 30 chars) or too long (> 60 chars) | -10 |
285
484
  | Missing meta description | -30 |
@@ -289,14 +488,13 @@ Supported plugins:
289
488
 
290
489
  ### Exposing SEO Meta Fields (Required)
291
490
 
292
- Most SEO plugins store their data in WordPress post meta fields that are **not exposed via the REST API by default**. Without this step, `wp_get_seo_meta` and `wp_audit_seo` will return empty results even though your SEO data exists in the database.
491
+ Most SEO plugins store their data in WordPress post meta fields that are not exposed via the REST API by default. Without this step, `wp_get_seo_meta` and `wp_audit_seo` will return empty results even though your SEO data exists in the database.
293
492
 
294
493
  Add the following code to your theme's `functions.php` (Appearance → Theme File Editor → functions.php) or — preferably — create a custom mini-plugin (see below).
295
494
 
296
- > **Warning:** When pasting code into functions.php, make sure the file starts with exactly `<?php` — no extra characters before it. A stray character (like `<<?php`) will break the WordPress REST API by injecting invalid output before JSON responses, causing `Unexpected token '<'` errors in MCP.
495
+ > ⚠️ **Important:** When pasting code into `functions.php`, make sure the file starts with exactly `<?php` — no extra characters before it. A stray character (like `<<?php`) will break the WordPress REST API by injecting invalid output before JSON responses, causing `Unexpected token '<'` errors in MCP.
297
496
 
298
497
  **RankMath:**
299
-
300
498
  ```php
301
499
  add_action( 'init', function() {
302
500
  $fields = array(
@@ -325,7 +523,6 @@ add_action( 'init', function() {
325
523
  ```
326
524
 
327
525
  **Yoast SEO:**
328
-
329
526
  ```php
330
527
  add_action( 'init', function() {
331
528
  $fields = array(
@@ -355,7 +552,6 @@ add_action( 'init', function() {
355
552
  ```
356
553
 
357
554
  **SEOPress:**
358
-
359
555
  ```php
360
556
  add_action( 'init', function() {
361
557
  $fields = array(
@@ -384,7 +580,6 @@ add_action( 'init', function() {
384
580
  ```
385
581
 
386
582
  **All in One SEO:**
387
-
388
583
  ```php
389
584
  add_action( 'init', function() {
390
585
  $fields = array(
@@ -412,12 +607,11 @@ add_action( 'init', function() {
412
607
 
413
608
  ### Alternative: MCP SEO Bridge Plugin (Recommended)
414
609
 
415
- > **Note:** Core content operations require no WordPress plugin. SEO metadata tools may require exposing meta fields via the REST API using either a theme snippet or this optional micro-plugin.
610
+ > Note: Core content operations require no WordPress plugin. SEO metadata tools may require exposing meta fields via the REST API using either a theme snippet or this optional micro-plugin.
416
611
 
417
612
  Instead of modifying your theme's `functions.php` (which gets overwritten on theme updates), create a standalone micro-plugin.
418
613
 
419
614
  Create the file `wp-content/plugins/mcp-seo-bridge.php`:
420
-
421
615
  ```php
422
616
  <?php
423
617
  /**
@@ -431,7 +625,6 @@ Create the file `wp-content/plugins/mcp-seo-bridge.php`:
431
625
  if ( ! defined( 'ABSPATH' ) ) exit;
432
626
 
433
627
  add_action( 'init', function() {
434
- // Auto-detect SEO plugin and register appropriate fields
435
628
  $fields = array();
436
629
 
437
630
  if ( defined( 'RANK_MATH_VERSION' ) ) {
@@ -479,30 +672,51 @@ Activate it from WordPress Admin → Plugins. This approach auto-detects your SE
479
672
  ### Verifying SEO Fields Are Exposed
480
673
 
481
674
  After adding the code, verify the fields are accessible:
482
-
483
675
  ```bash
484
676
  curl -s -u "username:application-password" \
485
677
  "https://yoursite.com/wp-json/wp/v2/posts?per_page=1" | python3 -m json.tool | grep -E "rank_math|yoast|seopress|aioseo"
486
678
  ```
487
679
 
488
- If you see your SEO fields in the meta object, the configuration is working.
680
+ If you see your SEO fields in the `meta` object, the configuration is working.
489
681
 
490
682
  ### Troubleshooting SEO Fields
491
683
 
492
684
  | Symptom | Cause | Fix |
493
- |---------|-------|-----|
494
- | wp_audit_seo returns empty SEO data | Meta fields not exposed via REST API | Add register_post_meta() code above |
495
- | Unexpected token '<' on all MCP calls | Stray character before `<?php` in functions.php | Remove any characters before `<?php` |
685
+ |---|---|---|
686
+ | `wp_audit_seo` returns empty SEO data | Meta fields not exposed via REST API | Add `register_post_meta()` code above |
687
+ | `Unexpected token '<'` on all MCP calls | Stray character before `<?php` in `functions.php` | Remove any characters before `<?php` |
496
688
  | SEO fields visible but all null | SEO plugin not yet configured on those posts | Set titles/descriptions in RankMath/Yoast editor |
497
689
  | No SEO plugin detected | Plugin constant not matched | Verify your SEO plugin is active |
498
- | Fields lost after theme update | Code was in functions.php | Use the MCP SEO Bridge plugin instead |
690
+ | Fields lost after theme update | Code was in `functions.php` | Use the MCP SEO Bridge plugin instead |
499
691
 
500
692
  ---
501
693
 
502
- ## Testing
694
+ ## WooCommerce Setup
503
695
 
504
- 171 unit tests covering all 35 tools — zero network calls, fully mocked.
696
+ ### Generate API Keys
505
697
 
698
+ Go to WooCommerce → Settings → Advanced → REST API → Add key.
699
+
700
+ Set permissions to **Read/Write** if you plan to use `wc_update_product` or `wc_update_order_status`. Set to **Read** for a read-only WooCommerce integration.
701
+ ```env
702
+ WC_CONSUMER_KEY=ck_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
703
+ WC_CONSUMER_SECRET=cs_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
704
+ ```
705
+
706
+ ### Price Guardrail
707
+
708
+ `wc_price_guardrail` analyzes proposed price changes before any write operation. It returns `safe` or `unsafe` based on a configurable threshold (default 20%). Claude should call this tool before `wc_update_product` when modifying prices.
709
+ ```env
710
+ WC_PRICE_GUARDRAIL_THRESHOLD=20 # percentage — changes above this require explicit override
711
+ ```
712
+
713
+ `wc_price_guardrail` is always allowed regardless of `WP_READ_ONLY`. It never modifies data.
714
+
715
+ ---
716
+
717
+ ## Testing
718
+
719
+ 674 unit tests covering all 85 tools — zero network calls, fully mocked.
506
720
  ```bash
507
721
  npm test # run all tests (vitest)
508
722
  npm run test:watch # watch mode
@@ -510,20 +724,39 @@ npm run test:coverage # coverage report
510
724
  ```
511
725
 
512
726
  | Test file | Scope | Tests |
513
- |-----------|-------|-------|
514
- | governance.test.js | 4 governance flags + combinations | 24 |
515
- | posts.test.js | list, get, create, update, delete, search | 18 |
516
- | pages.test.js | list, get, create, update | 12 |
517
- | media.test.js | list, get, upload | 14 |
518
- | taxonomies.test.js | categories, tags, create term | 16 |
519
- | comments.test.js | list, create | 12 |
520
- | users.test.js | list | 7 |
521
- | search.test.js | search, post types, custom posts | 10 |
522
- | seo.test.js | get, update, audit | 12 |
523
- | plugins.test.js | list, activate, deactivate | 16 |
524
- | themes.test.js | list, get | 8 |
525
- | revisions.test.js | list, get, restore, delete | 17 |
526
- | site.test.js | site info, set target | 5 |
727
+ |---|---|---|
728
+ | `governance.test.js` | All governance flags + combinations including `WP_REQUIRE_APPROVAL` and `WP_CONFIRM_DESTRUCTIVE` | 30 |
729
+ | `posts.test.js` | list, get, create, update, delete, search | 18 |
730
+ | `pages.test.js` | list, get, create, update | 12 |
731
+ | `media.test.js` | list, get, upload | 14 |
732
+ | `taxonomies.test.js` | categories, tags, create term | 16 |
733
+ | `comments.test.js` | list, create | 12 |
734
+ | `users.test.js` | list | 7 |
735
+ | `search.test.js` | search, post types, custom posts | 10 |
736
+ | `seo.test.js` | get, update, audit | 12 |
737
+ | `plugins.test.js` | list, activate, deactivate | 16 |
738
+ | `themes.test.js` | list, get | 8 |
739
+ | `revisions.test.js` | list, get, restore, delete | 17 |
740
+ | `editorial.test.js` | submit_for_review, approve, reject | 15 |
741
+ | `links.test.js` | analyze_links, suggest_internal_links | 16 |
742
+ | `woocommerce.test.js` | products, orders, customers, coupons, reports, write, guardrail | 40 |
743
+ | `auditMediaSeo.test.js` | media alt text audit, filename scoring | 12 |
744
+ | `findOrphanPages.test.js` | inbound link detection, exclusion list | 10 |
745
+ | `auditHeadingStructure.test.js` | H1/H2/H3 hierarchy, level skips, keyword detection | 12 |
746
+ | `findThinContent.test.js` | word count threshold, heading density | 10 |
747
+ | `auditCanonicals.test.js` | canonical validation, mismatch detection, multi-plugin | 12 |
748
+ | `analyzeEeatSignals.test.js` | E-E-A-T scoring, author bio, citations, structured data | 12 |
749
+ | `findBrokenInternalLinks.test.js` | HEAD request batching, 4xx/3xx detection | 12 |
750
+ | `findKeywordCannibalization.test.js` | focus keyword conflicts, multi-plugin detection | 10 |
751
+ | `auditTaxonomies.test.js` | Levenshtein duplicates, unused terms, over-tagging | 12 |
752
+ | `auditOutboundLinks.test.js` | external link profile, nofollow detection | 10 |
753
+ | `contentAnalyzer.test.js` | readability, TF-IDF, cosine similarity, entities, text diff | 44 |
754
+ | `contentIntelligence.test.js` | 16 content intelligence tools: brief, outline, readability, update frequency, link map, anchor texts, schema, structure, duplicates, gaps, FAQ, CTA, entities, velocity, revisions diff, word count | 125 |
755
+ | `site.test.js` | site info, set target | 5 |
756
+ | `transport/http.test.js` | HTTP transport, Bearer auth, sessions | 10 |
757
+ | `pluginDetector.test.js` | SEO plugin detection, rendered head, HTML head parsing | 13 |
758
+ | `pluginIntelligence.test.js` | 6 plugin intelligence tools: rendered head, rendered SEO audit, pillar content, schema plugins, SEO score, Twitter meta | 48 |
759
+ | `dxt/manifest.test.js` | MCPB manifest validation, 85 tools declared | 10 |
527
760
 
528
761
  Each test verifies: success response shape, governance blocking (write tools), HTTP error handling (403/404), and audit log entries.
529
762
 
@@ -532,10 +765,9 @@ Each test verifies: success response shape, governance blocking (write tools), H
532
765
  ## Structured Audit Log
533
766
 
534
767
  Every tool invocation is recorded as a JSON event on stderr — ready for ingestion into Datadog, Splunk, CloudWatch, Langfuse, ELK, or any JSON-compatible pipeline.
535
-
536
768
  ```json
537
769
  {
538
- "timestamp": "2026-02-16T18:42:00.000Z",
770
+ "timestamp": "2026-02-19T18:42:00.000Z",
539
771
  "tool": "wp_create_post",
540
772
  "target": 1234,
541
773
  "target_type": "post",
@@ -548,20 +780,20 @@ Every tool invocation is recorded as a JSON event on stderr — ready for ingest
548
780
  }
549
781
  ```
550
782
 
551
- 35 instrumentation points across all tools. Three status types: `success`, `error`, `blocked`.
783
+ 79 instrumentation points across all tools. Three status types: `success`, `error`, `blocked`.
552
784
 
553
785
  | Field | Description |
554
- |-------|-------------|
555
- | timestamp | ISO 8601 |
556
- | tool | Tool name invoked |
557
- | target | Resource ID when applicable |
558
- | target_type | Resource type (post, page, media, comment, category, tag, plugin, theme, revision) |
559
- | action | Operation: list, read, create, update, trash, permanent_delete, upload, search, switch_target, read_seo, update_seo, audit_seo, activate, deactivate, restore |
560
- | status | success, error, or blocked |
561
- | latency_ms | Execution time |
562
- | site | Active target name |
563
- | params | Sanitized parameters (content fields truncated) |
564
- | error | Error detail or null |
786
+ |---|---|
787
+ | `timestamp` | ISO 8601 |
788
+ | `tool` | Tool name invoked |
789
+ | `target` | Resource ID when applicable |
790
+ | `target_type` | Resource type (post, page, media, comment, category, tag, plugin, theme, revision, product, order, customer, coupon) |
791
+ | `action` | Operation: list, read, create, update, trash, permanent_delete, upload, search, switch_target, read_seo, update_seo, audit_seo, activate, deactivate, restore, submit_review, approve, reject, analyze_links, suggest_links, guardrail, audit_media_seo, find_orphans, audit_headings, find_thin_content, audit_canonicals, analyze_eeat, find_broken_links, find_cannibalization, audit_taxonomies, audit_outbound_links, content_brief, extract_outline, audit_readability, audit_update_frequency, build_link_map, audit_anchor_texts, audit_schema, audit_content_structure, find_duplicates, find_content_gaps, extract_faq, audit_cta, extract_entities, publishing_velocity, compare_revisions, list_by_word_count |
792
+ | `status` | `success`, `error`, or `blocked` |
793
+ | `latency_ms` | Execution time |
794
+ | `site` | Active target name |
795
+ | `params` | Sanitized parameters (content fields truncated) |
796
+ | `error` | Error detail or null |
565
797
 
566
798
  ---
567
799
 
@@ -570,17 +802,14 @@ Every tool invocation is recorded as a JSON event on stderr — ready for ingest
570
802
  Manage multiple WordPress sites from a single server instance. Designed for agencies and multi-brand organizations.
571
803
 
572
804
  **Inline configuration:**
573
-
574
805
  ```bash
575
806
  WP_TARGETS_JSON='{"production":{"url":"https://mysite.com","username":"admin","password":"xxxx"},"staging":{"url":"https://staging.mysite.com","username":"editor","password":"xxxx"}}'
576
807
  ```
577
808
 
578
809
  **File-based configuration:**
579
-
580
810
  ```bash
581
811
  WP_TARGETS_FILE=/path/to/targets.json
582
812
  ```
583
-
584
813
  ```json
585
814
  {
586
815
  "production": {
@@ -610,46 +839,55 @@ Switch targets during a session with `wp_set_target`. All available sites and th
610
839
  The server performs a health check on startup: REST API connectivity, user authentication, and role verification. During operation: automatic retry with exponential backoff (configurable, default 3 attempts), request timeout (default 30s), rate limit handling (respects 429 + retry-after), and contextual error messages with diagnosis guidance.
611
840
 
612
841
  | Setting | Default | Description |
613
- |---------|---------|-------------|
614
- | WP_MCP_VERBOSE | false | Debug-level logging |
615
- | WP_MCP_TIMEOUT | 30000 | Request timeout (ms) |
616
- | WP_MCP_MAX_RETRIES | 3 | Max retry attempts |
842
+ |---|---|---|
843
+ | `WP_MCP_VERBOSE` | `false` | Debug-level logging |
844
+ | `WP_MCP_TIMEOUT` | `30000` | Request timeout (ms) |
845
+ | `WP_MCP_MAX_RETRIES` | `3` | Max retry attempts |
617
846
 
618
847
  ---
619
848
 
620
849
  ## Security
621
850
 
622
- - **HTTPS required** in production. HTTP only for localhost
623
- - **Application Passwords only** — never use WordPress login credentials
624
- - **Credentials never logged** — audit trail sanitizes all sensitive data
625
- - **No credentials in code**.env or environment variables only
626
- - **Instant revocation** — Application Passwords can be revoked from WordPress admin
627
- - **Traceable requests** — custom User-Agent: WordPress-MCP-Server/2.2.0
851
+ - HTTPS required in production. HTTP only for localhost
852
+ - Application Passwords only — never use WordPress login credentials
853
+ - Credentials never logged — audit trail sanitizes all sensitive data
854
+ - No credentials in code — `.env` or environment variables only
855
+ - Instant revocation — Application Passwords can be revoked from WordPress admin
856
+ - Traceable requests — custom `User-Agent: WordPress-MCP-Server/4.4.0`
857
+ - Bearer token auth in HTTP mode — timing-safe comparison, no token in logs
858
+ - Origin validation in HTTP mode — anti-DNS-rebinding protection
628
859
 
629
860
  ---
630
861
 
631
862
  ## Troubleshooting
632
863
 
633
864
  | Issue | Solution |
634
- |-------|----------|
635
- | 401 Unauthorized | Verify username and Application Password |
636
- | 403 Forbidden | Check WordPress user role and capabilities |
637
- | 404 Not Found | Verify WP_API_URL and REST API availability |
638
- | Unexpected token '<' | Stray character before `<?php` in functions.php — see [SEO Troubleshooting](#troubleshooting-seo-fields) |
639
- | Blocked: READ-ONLY mode | Disable WP_READ_ONLY to allow writes |
640
- | Blocked: DRAFT-ONLY mode | Only draft/pending allowed. Check WP_DRAFT_ONLY |
641
- | Blocked: PLUGIN MANAGEMENT | Disable WP_DISABLE_PLUGIN_MANAGEMENT to allow activate/deactivate |
642
- | Rate limit exceeded | Adjust WP_MAX_CALLS_PER_MINUTE |
643
- | Timeout | Increase WP_MCP_TIMEOUT or check server |
644
- | Site not found | Verify site key in WP_TARGETS_JSON or file |
865
+ |---|---|
866
+ | `401 Unauthorized` | Verify username and Application Password |
867
+ | `403 Forbidden` | Check WordPress user role and capabilities |
868
+ | `404 Not Found` | Verify `WP_API_URL` and REST API availability |
869
+ | `Unexpected token '<'` | Stray character before `<?php` in `functions.php` — see SEO Troubleshooting |
870
+ | `Blocked: READ-ONLY mode` | Disable `WP_READ_ONLY` to allow writes |
871
+ | `Blocked: DRAFT-ONLY mode` | Only draft/pending allowed. Check `WP_DRAFT_ONLY` |
872
+ | `Blocked: PLUGIN MANAGEMENT` | Disable `WP_DISABLE_PLUGIN_MANAGEMENT` to allow activate/deactivate |
873
+ | `Blocked: APPROVAL REQUIRED` | `WP_REQUIRE_APPROVAL=true` use `wp_submit_for_review` then `wp_approve_post` |
874
+ | Confirmation token required | `WP_CONFIRM_DESTRUCTIVE=true` pass the returned token on a second call within 60s |
875
+ | `401 Unauthorized (HTTP mode)` | Set `MCP_AUTH_TOKEN` and pass `Authorization: Bearer <token>` |
876
+ | `403 Forbidden (HTTP mode)` | Check `MCP_ALLOWED_ORIGINS` includes your client origin |
877
+ | WooCommerce 401 | Verify `WC_CONSUMER_KEY` and `WC_CONSUMER_SECRET` |
878
+ | WooCommerce 403 | API key needs Read/Write permissions for write tools |
879
+ | Rate limit exceeded | Adjust `WP_MAX_CALLS_PER_MINUTE` |
880
+ | Timeout | Increase `WP_MCP_TIMEOUT` or check server |
881
+ | Site not found | Verify site key in `WP_TARGETS_JSON` or file |
645
882
  | No SEO plugin detected | Install Yoast, RankMath, SEOPress, or AIOSEO |
646
- | SEO meta fields empty | Add register_post_meta() code or install MCP SEO Bridge plugin — see [Exposing SEO Meta Fields](#exposing-seo-meta-fields-required) |
883
+ | SEO meta fields empty | Add `register_post_meta()` code or install MCP SEO Bridge plugin — see Exposing SEO Meta Fields |
884
+ | `wp_find_broken_internal_links` slow | Reduce `batchSize` parameter or increase `timeoutMs` |
885
+ | `wp_audit_outbound_links` empty | External HEAD requests blocked by your server firewall |
647
886
  | Server not starting | Check Node.js 18+ is installed: `node --version` |
648
887
 
649
888
  ---
650
889
 
651
890
  ## Development
652
-
653
891
  ```bash
654
892
  # Clone the repository
655
893
  git clone https://github.com/GeorgesAdSim/wordpress-mcp-server.git
@@ -661,15 +899,25 @@ npm install
661
899
  # Run tests
662
900
  npm test
663
901
 
664
- # Run locally
902
+ # Run locally (stdio)
903
+ WP_API_URL="https://your-site.com" \
904
+ WP_API_USERNAME="user" \
905
+ WP_API_PASSWORD="xxxx xxxx xxxx xxxx" \
906
+ node index.js
907
+
908
+ # Run locally (HTTP)
909
+ MCP_TRANSPORT=http \
910
+ MCP_AUTH_TOKEN=dev-token \
665
911
  WP_API_URL="https://your-site.com" \
666
912
  WP_API_USERNAME="user" \
667
913
  WP_API_PASSWORD="xxxx xxxx xxxx xxxx" \
668
914
  node index.js
915
+
916
+ # Build MCPB bundle
917
+ npm run build:mcpb
669
918
  ```
670
919
 
671
920
  ### Testing with MCP Inspector
672
-
673
921
  ```bash
674
922
  npx @modelcontextprotocol/inspector node index.js
675
923
  ```
@@ -678,15 +926,156 @@ npx @modelcontextprotocol/inspector node index.js
678
926
 
679
927
  ## Changelog
680
928
 
929
+ ### v4.5.0 (2026-02-21) — Plugin Intelligence (RankMath + Yoast)
930
+
931
+ 6 new tools exploiting native RankMath and Yoast SEO API endpoints for rendered head analysis, schema validation, and social meta management.
932
+
933
+ **New shared module:**
934
+ - `src/pluginDetector.js` — SEO plugin auto-detection via REST API namespace discovery (cached), rendered head fetching, HTML head parsing
935
+
936
+ **Rendered SEO Analysis:**
937
+ - `wp_get_rendered_head` — fetch the real `<head>` HTML via RankMath `/rankmath/v1/getHead` or Yoast `/yoast/v1/get_head` endpoints, compare rendered vs stored meta
938
+ - `wp_audit_rendered_seo` — bulk audit rendered vs stored SEO meta divergences with per-post scoring (title/description/canonical/robots/schema mismatches)
939
+
940
+ **Plugin-Native Features:**
941
+ - `wp_get_pillar_content` — read/write RankMath `rank_math_pillar_content` cornerstone flag. Write mode blocked by `WP_READ_ONLY`
942
+ - `wp_audit_schema_plugins` — validate JSON-LD schemas from plugin native fields (`rank_math_schema` or Yoast `yoast_head_json`). Checks required fields per @type
943
+ - `wp_get_seo_score` — read RankMath native SEO score (0-100) with bulk mode distribution stats
944
+ - `wp_get_twitter_meta` — read/write Twitter Card meta (title, description, image) for RankMath, Yoast, and SEOPress. Write mode blocked by `WP_READ_ONLY`
945
+
946
+ 674 Vitest unit tests · 85 tools
947
+
948
+ ### v4.4.0 (2026-02-21) — Content Intelligence
949
+
950
+ 16 new read-only analysis tools for deep content intelligence without any WordPress plugin.
951
+
952
+ **Foundations:**
953
+ - `src/contentAnalyzer.js` — shared analysis engine: readability (Flesch-Kincaid FR), TF-IDF, cosine similarity, entity extraction, text diff, content structure detection
954
+ - `wp_get_content_brief` — editorial brief aggregator (SEO + structure + links in 1 call)
955
+ - `wp_extract_post_outline` — H1-H6 outline extraction with category-level pattern analysis
956
+
957
+ **SEO Advanced:**
958
+ - `wp_audit_readability` — bulk Flesch-Kincaid FR scoring with transition word and passive voice analysis
959
+ - `wp_audit_update_frequency` — outdated content detection cross-referenced with SEO scores
960
+ - `wp_build_link_map` — internal link matrix with simplified PageRank scoring (0-100)
961
+
962
+ **Technical Quality:**
963
+ - `wp_audit_anchor_texts` — anchor text diversity audit: generic, over-optimized, image link detection
964
+ - `wp_audit_schema_markup` — JSON-LD schema.org detection and validation (Article, FAQ, HowTo, LocalBusiness)
965
+ - `wp_audit_content_structure` — editorial structure scoring (0-100): intro, conclusion, FAQ, TOC, lists, images
966
+
967
+ **Intelligence Advanced:**
968
+ - `wp_find_duplicate_content` — TF-IDF cosine similarity for near-duplicate detection with union-find clustering
969
+ - `wp_find_content_gaps` — taxonomy under-representation analysis (categories + tags)
970
+ - `wp_extract_faq_blocks` — FAQ inventory: JSON-LD, Gutenberg blocks, HTML patterns
971
+ - `wp_audit_cta_presence` — CTA detection (6 types) with scoring 0-100
972
+ - `wp_extract_entities` — regex/heuristic named entity extraction (brands, locations, persons, organizations)
973
+ - `wp_get_publishing_velocity` — publication cadence by author/category with trend detection
974
+ - `wp_compare_revisions_diff` — textual diff between revisions with amplitude scoring
975
+ - `wp_list_posts_by_word_count` — posts sorted by length with 6-tier segmentation
976
+
977
+ All Content Intelligence tools are read-only and always allowed regardless of governance flags.
978
+
979
+ 613 Vitest unit tests · 79 tools
980
+
981
+ ### v4.2.0 (2026-02-19) — SEO Audit Suite (Sprint 3)
982
+
983
+ - `wp_find_broken_internal_links` — HEAD request link checker with configurable batch size and timeout. Returns broken (4xx/5xx), redirected (3xx), and slow links
984
+ - `wp_find_keyword_cannibalization` — detect posts sharing the same focus keyword. Auto-detects RankMath/Yoast/SEOPress/AIOSEO. Groups conflicts by keyword, flags weakest post by word count
985
+ - `wp_audit_taxonomies` — taxonomy bloat detection: unused terms, near-duplicate detection via Levenshtein distance, single-post terms, over-tagged posts
986
+ - `wp_audit_outbound_links` — external link profile per post: low-authority domains, missing rel="nofollow", broken external URLs
987
+ - `src/htmlParser.js` — shared HTML parsing service (parseImagesFromHtml, extractHeadings, extractInternalLinks, countWords)
988
+ - 400 Vitest unit tests · 63 tools
989
+
990
+ ### v4.1.0 (2026-02-19) — SEO Audit Suite (Sprint 2)
991
+
992
+ - `wp_find_thin_content` — surface posts below configurable word count threshold. Scores content quality by word count, heading density, and paragraph structure
993
+ - `wp_audit_canonicals` — validate canonical URLs across posts and pages. Detects missing canonicals, self-referencing mismatches, cross-domain canonicals. Auto-detects RankMath/Yoast/SEOPress/AIOSEO
994
+ - `wp_analyze_eeat_signals` — E-E-A-T scoring per post (0-100): author bio presence, publication/update dates, outbound citations, word count, structured data markers
995
+ - 368 Vitest unit tests · 59 tools
996
+
997
+ ### v4.0.0 (2026-02-19) — SEO Audit Suite (Sprint 1)
998
+
999
+ - `wp_audit_media_seo` — audit media library for missing alt text, short alt text, unoptimized filenames. Returns per-image scores and prioritized fix list
1000
+ - `wp_find_orphan_pages` — identify posts with no internal links pointing to them, sorted by word count. Configurable minimum word threshold and exclusion list
1001
+ - `wp_audit_heading_structure` — analyze H1/H2/H3 hierarchy in post content. Detects H1 in body, heading level skips, empty headings, focus keyword absent from H2
1002
+ - All 10 SEO audit tools are read-only and always allowed regardless of governance flags
1003
+ - 340 Vitest unit tests · 56 tools
1004
+
1005
+ ### v3.6.0 (2026-02-19) — WooCommerce Write
1006
+
1007
+ - `wc_update_product` — update product fields (title, description, price, stock, status). Integrated with `wc_price_guardrail` threshold enforcement
1008
+ - `wc_update_order_status` — transition order status (e.g., processing → completed)
1009
+ - `WC_PRICE_GUARDRAIL_THRESHOLD` — configurable price change safety threshold (default 20%)
1010
+ - All WooCommerce write tools blocked by `WP_READ_ONLY`
1011
+ - 305 Vitest unit tests · 53 tools
1012
+
1013
+ ### v3.5.0 (2026-02-19) — WooCommerce Intelligence
1014
+
1015
+ - `wc_get_customer` — customer profile with order history summary and lifetime value
1016
+ - `wc_list_coupons` / `wc_get_coupon` — coupon management with discount rules and usage stats
1017
+ - `wc_sales_report` — revenue, orders, and average order value for a date range
1018
+ - `wc_top_products` — ranking by revenue, quantity sold, or order count
1019
+ - 287 Vitest unit tests · 50 tools
1020
+
1021
+ ### v3.4.0 (2026-02-19) — WooCommerce Core
1022
+
1023
+ - `wc_list_products` / `wc_get_product` — product catalog with variation support
1024
+ - `wc_list_orders` / `wc_get_order` — order management with full line item detail
1025
+ - `wc_list_customers` — customer list with search and role filtering
1026
+ - `wc_price_guardrail` — read-only price change safety analysis
1027
+ - Requires `WC_CONSUMER_KEY` and `WC_CONSUMER_SECRET`
1028
+ - 271 Vitest unit tests · 46 tools
1029
+
1030
+ ### v3.3.0 (2026-02-19) — Internal Link Intelligence
1031
+
1032
+ - `wp_analyze_links` — audit all internal/external links in a post. HEAD request verification per link (broken/warning/unknown). Max 20 checks, configurable timeout
1033
+ - `wp_suggest_internal_links` — semantic link suggestions scored by category match (+3), freshness (+3/2/1), SEO focus keyword match (+2), title match (+2). Excludes already-linked posts
1034
+ - `src/linkUtils.js` — 6 shared utilities: extractInternalLinks, extractExternalLinks, checkLinkStatus, extractFocusKeyword (auto-detects RankMath/Yoast/SEOPress/AIOSEO), calculateRelevanceScore, suggestAnchorText
1035
+ - Pre-flight linking workflow: suggest → user validates → `wp_update_post` (never auto-insert)
1036
+ - 253 Vitest unit tests · 40 tools
1037
+
1038
+ ### v3.2.0 (2026-02-19) — Governance Workflows
1039
+
1040
+ - Editorial approval workflow: `wp_submit_for_review` (draft → pending), `wp_approve_post` (pending → publish), `wp_reject_post` (pending → draft + mandatory reason)
1041
+ - New governance flag: `WP_REQUIRE_APPROVAL` — blocks direct publish, forces approval workflow
1042
+ - Two-step confirmation for destructive operations: `wp_delete_post` and `wp_delete_revision` return a stateless token (60s TTL, SHA-256) when `WP_CONFIRM_DESTRUCTIVE=true`
1043
+ - New governance flag: `WP_CONFIRM_DESTRUCTIVE` — requires explicit token confirmation before any delete
1044
+ - `src/confirmationToken.js` — stateless token system, zero persistence
1045
+ - Governance priority: `WP_READ_ONLY` → `WP_DISABLE_DELETE` → `WP_CONFIRM_DESTRUCTIVE`
1046
+ - 225 Vitest unit tests · 38 tools
1047
+
1048
+ ### v3.1.0 (2026-02-19) — MCPB Bundle
1049
+
1050
+ - `dxt/manifest.json` — MCPB v0.3 spec, 35 tools declared
1051
+ - WordPress credentials stored in OS keychain (`sensitive: true`)
1052
+ - `npm run build:mcpb` — build script for `.mcpb` distribution
1053
+ - 10 new manifest validation tests (201 total)
1054
+ - Published to npm: `npx -y @adsim/wordpress-mcp-server@3.1.0`
1055
+
1056
+ ### v3.0.0 (2026-02-19) — HTTP Streamable Transport
1057
+
1058
+ - HTTP Streamable transport (MCP spec 2025-03-26) via `MCP_TRANSPORT=http`
1059
+ - Bearer token authentication with timing-safe comparison (`MCP_AUTH_TOKEN`)
1060
+ - Session management via `Mcp-Session-Id` header (UUID v4)
1061
+ - Origin header validation (anti-DNS-rebinding)
1062
+ - Health endpoint `GET /health`
1063
+ - Dual mode `MCP_DUAL_MODE=true` — stdio + HTTP simultaneously
1064
+ - Graceful shutdown SIGTERM/SIGINT across both transports
1065
+ - 10 new HTTP/auth unit tests (191 total)
1066
+ - Published to npm: `@adsim/wordpress-mcp-server`
1067
+
681
1068
  ### v2.2.0 (2026-02-19) — Enterprise Edition
682
- - **9 new tools**: plugins (list/activate/deactivate), themes (list/get), revisions (list/get/restore/delete)
683
- - **New governance flag**: `WP_DISABLE_PLUGIN_MANAGEMENT`
684
- - **171 Vitest unit tests** covering all 35 tools (governance, success, 403/404, audit logs)
685
- - **GitHub Actions CI** workflow
1069
+
1070
+ - 9 new tools: plugins (list/activate/deactivate), themes (list/get), revisions (list/get/restore/delete)
1071
+ - New governance flag: `WP_DISABLE_PLUGIN_MANAGEMENT`
1072
+ - 171 Vitest unit tests covering all 35 tools (governance, success, 403/404, audit logs)
1073
+ - GitHub Actions CI workflow
686
1074
  - Governance functions read env at call time for testability
687
1075
  - Exported `handleToolCall` for direct testing
688
1076
 
689
1077
  ### v2.1.0 (2026-02-16)
1078
+
690
1079
  - Enterprise governance controls (read-only, draft-only, type/status allowlists)
691
1080
  - Structured JSON audit trail (27 instrumentation points)
692
1081
  - Multi-target site management
@@ -695,26 +1084,25 @@ npx @modelcontextprotocol/inspector node index.js
695
1084
  - Health checks, retry with backoff, rate limiting
696
1085
 
697
1086
  ### v1.0.0 (2025-10-17)
1087
+
698
1088
  - Initial release — JavaScript, 5 tools (list, get, create, update, search posts)
699
1089
 
700
1090
  ---
701
1091
 
702
1092
  ## Roadmap
703
1093
 
704
- ### v2.3Governance Workflows
705
- - Approval workflow: draft human review publish
706
- - Confirmation step for destructive actions
707
- - Per-target enterprise controls
1094
+ ### v4.5GSC Integration
1095
+ - `wp_get_gsc_performance` Google Search Console API (clicks, impressions, position, CTR per URL)
1096
+ - `wp_find_quick_win_keywords` surface keywords ranking positions 11–20 for targeted updates
1097
+ - `wp_seo_content_decay` — cross-reference GSC traffic loss with content age to prioritize refresh candidates
708
1098
 
709
- ### v2.4Extended Integrations
710
- - OAuth 2.0 / JWT authentication
711
- - WooCommerce support (products, orders)
712
- - Media management (bulk, transforms)
1099
+ ### v4.6Redirect Intelligence
1100
+ - `wp_create_redirect` create 301 redirects via Redirection plugin or RankMath/Yoast Redirects. Auto-triggered governance hook when `wp_update_post` changes a slug
1101
+ - `wp_list_404_errors` surface recent 404s from Redirection plugin log
713
1102
 
714
- ### v2.5Distribution
715
- - npm: `npx @adsim/wordpress-mcp-server`
1103
+ ### v4.7OAuth & Registry
1104
+ - OAuth 2.0 / JWT authentication
716
1105
  - MCP Registry submission
717
- - TypeScript rewrite
718
1106
 
719
1107
  ---
720
1108