@adsim/wordpress-mcp-server 3.1.0 → 4.4.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 (31) hide show
  1. package/README.md +543 -176
  2. package/dxt/manifest.json +86 -9
  3. package/index.js +3156 -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/utils/contentCompressor.js +116 -0
  10. package/src/woocommerceClient.js +88 -0
  11. package/tests/unit/contentAnalyzer.test.js +397 -0
  12. package/tests/unit/tools/analyzeEeatSignals.test.js +192 -0
  13. package/tests/unit/tools/approval.test.js +251 -0
  14. package/tests/unit/tools/auditCanonicals.test.js +149 -0
  15. package/tests/unit/tools/auditHeadingStructure.test.js +150 -0
  16. package/tests/unit/tools/auditMediaSeo.test.js +123 -0
  17. package/tests/unit/tools/auditOutboundLinks.test.js +175 -0
  18. package/tests/unit/tools/auditTaxonomies.test.js +173 -0
  19. package/tests/unit/tools/contentCompressor.test.js +320 -0
  20. package/tests/unit/tools/contentIntelligence.test.js +2168 -0
  21. package/tests/unit/tools/destructive.test.js +246 -0
  22. package/tests/unit/tools/findBrokenInternalLinks.test.js +222 -0
  23. package/tests/unit/tools/findKeywordCannibalization.test.js +183 -0
  24. package/tests/unit/tools/findOrphanPages.test.js +145 -0
  25. package/tests/unit/tools/findThinContent.test.js +145 -0
  26. package/tests/unit/tools/internalLinks.test.js +283 -0
  27. package/tests/unit/tools/perTargetControls.test.js +228 -0
  28. package/tests/unit/tools/site.test.js +6 -1
  29. package/tests/unit/tools/woocommerce.test.js +344 -0
  30. package/tests/unit/tools/woocommerceIntelligence.test.js +341 -0
  31. 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-613%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.4.0 Enterprise** · 79 tools · 613 Vitest tests · GitHub Actions CI · HTTP Streamable transport · MCPB bundle · SEO metadata · SEO audit suite · Content 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)
74
+
75
+ ### Install from npm (recommended)
76
+ ```bash
77
+ # Run directly — no install needed
78
+ npx -y @adsim/wordpress-mcp-server
71
79
 
72
- ### Install
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
+ }
192
+ ```
193
+
194
+ ---
195
+
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
123
206
  ```
124
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
+
125
215
  ---
126
216
 
127
- ## Available Tools (35)
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
+ 613 unit tests covering all 79 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,37 @@ 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
+ | `dxt/manifest.test.js` | MCPB manifest validation, 79 tools declared | 10 |
527
758
 
528
759
  Each test verifies: success response shape, governance blocking (write tools), HTTP error handling (403/404), and audit log entries.
529
760
 
@@ -532,10 +763,9 @@ Each test verifies: success response shape, governance blocking (write tools), H
532
763
  ## Structured Audit Log
533
764
 
534
765
  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
766
  ```json
537
767
  {
538
- "timestamp": "2026-02-16T18:42:00.000Z",
768
+ "timestamp": "2026-02-19T18:42:00.000Z",
539
769
  "tool": "wp_create_post",
540
770
  "target": 1234,
541
771
  "target_type": "post",
@@ -548,20 +778,20 @@ Every tool invocation is recorded as a JSON event on stderr — ready for ingest
548
778
  }
549
779
  ```
550
780
 
551
- 35 instrumentation points across all tools. Three status types: `success`, `error`, `blocked`.
781
+ 79 instrumentation points across all tools. Three status types: `success`, `error`, `blocked`.
552
782
 
553
783
  | 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 |
784
+ |---|---|
785
+ | `timestamp` | ISO 8601 |
786
+ | `tool` | Tool name invoked |
787
+ | `target` | Resource ID when applicable |
788
+ | `target_type` | Resource type (post, page, media, comment, category, tag, plugin, theme, revision, product, order, customer, coupon) |
789
+ | `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 |
790
+ | `status` | `success`, `error`, or `blocked` |
791
+ | `latency_ms` | Execution time |
792
+ | `site` | Active target name |
793
+ | `params` | Sanitized parameters (content fields truncated) |
794
+ | `error` | Error detail or null |
565
795
 
566
796
  ---
567
797
 
@@ -570,17 +800,14 @@ Every tool invocation is recorded as a JSON event on stderr — ready for ingest
570
800
  Manage multiple WordPress sites from a single server instance. Designed for agencies and multi-brand organizations.
571
801
 
572
802
  **Inline configuration:**
573
-
574
803
  ```bash
575
804
  WP_TARGETS_JSON='{"production":{"url":"https://mysite.com","username":"admin","password":"xxxx"},"staging":{"url":"https://staging.mysite.com","username":"editor","password":"xxxx"}}'
576
805
  ```
577
806
 
578
807
  **File-based configuration:**
579
-
580
808
  ```bash
581
809
  WP_TARGETS_FILE=/path/to/targets.json
582
810
  ```
583
-
584
811
  ```json
585
812
  {
586
813
  "production": {
@@ -610,46 +837,55 @@ Switch targets during a session with `wp_set_target`. All available sites and th
610
837
  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
838
 
612
839
  | 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 |
840
+ |---|---|---|
841
+ | `WP_MCP_VERBOSE` | `false` | Debug-level logging |
842
+ | `WP_MCP_TIMEOUT` | `30000` | Request timeout (ms) |
843
+ | `WP_MCP_MAX_RETRIES` | `3` | Max retry attempts |
617
844
 
618
845
  ---
619
846
 
620
847
  ## Security
621
848
 
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
849
+ - HTTPS required in production. HTTP only for localhost
850
+ - Application Passwords only — never use WordPress login credentials
851
+ - Credentials never logged — audit trail sanitizes all sensitive data
852
+ - No credentials in code — `.env` or environment variables only
853
+ - Instant revocation — Application Passwords can be revoked from WordPress admin
854
+ - Traceable requests — custom `User-Agent: WordPress-MCP-Server/4.4.0`
855
+ - Bearer token auth in HTTP mode — timing-safe comparison, no token in logs
856
+ - Origin validation in HTTP mode — anti-DNS-rebinding protection
628
857
 
629
858
  ---
630
859
 
631
860
  ## Troubleshooting
632
861
 
633
862
  | 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 |
863
+ |---|---|
864
+ | `401 Unauthorized` | Verify username and Application Password |
865
+ | `403 Forbidden` | Check WordPress user role and capabilities |
866
+ | `404 Not Found` | Verify `WP_API_URL` and REST API availability |
867
+ | `Unexpected token '<'` | Stray character before `<?php` in `functions.php` — see SEO Troubleshooting |
868
+ | `Blocked: READ-ONLY mode` | Disable `WP_READ_ONLY` to allow writes |
869
+ | `Blocked: DRAFT-ONLY mode` | Only draft/pending allowed. Check `WP_DRAFT_ONLY` |
870
+ | `Blocked: PLUGIN MANAGEMENT` | Disable `WP_DISABLE_PLUGIN_MANAGEMENT` to allow activate/deactivate |
871
+ | `Blocked: APPROVAL REQUIRED` | `WP_REQUIRE_APPROVAL=true` use `wp_submit_for_review` then `wp_approve_post` |
872
+ | Confirmation token required | `WP_CONFIRM_DESTRUCTIVE=true` pass the returned token on a second call within 60s |
873
+ | `401 Unauthorized (HTTP mode)` | Set `MCP_AUTH_TOKEN` and pass `Authorization: Bearer <token>` |
874
+ | `403 Forbidden (HTTP mode)` | Check `MCP_ALLOWED_ORIGINS` includes your client origin |
875
+ | WooCommerce 401 | Verify `WC_CONSUMER_KEY` and `WC_CONSUMER_SECRET` |
876
+ | WooCommerce 403 | API key needs Read/Write permissions for write tools |
877
+ | Rate limit exceeded | Adjust `WP_MAX_CALLS_PER_MINUTE` |
878
+ | Timeout | Increase `WP_MCP_TIMEOUT` or check server |
879
+ | Site not found | Verify site key in `WP_TARGETS_JSON` or file |
645
880
  | 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) |
881
+ | SEO meta fields empty | Add `register_post_meta()` code or install MCP SEO Bridge plugin — see Exposing SEO Meta Fields |
882
+ | `wp_find_broken_internal_links` slow | Reduce `batchSize` parameter or increase `timeoutMs` |
883
+ | `wp_audit_outbound_links` empty | External HEAD requests blocked by your server firewall |
647
884
  | Server not starting | Check Node.js 18+ is installed: `node --version` |
648
885
 
649
886
  ---
650
887
 
651
888
  ## Development
652
-
653
889
  ```bash
654
890
  # Clone the repository
655
891
  git clone https://github.com/GeorgesAdSim/wordpress-mcp-server.git
@@ -661,15 +897,25 @@ npm install
661
897
  # Run tests
662
898
  npm test
663
899
 
664
- # Run locally
900
+ # Run locally (stdio)
665
901
  WP_API_URL="https://your-site.com" \
666
902
  WP_API_USERNAME="user" \
667
903
  WP_API_PASSWORD="xxxx xxxx xxxx xxxx" \
668
904
  node index.js
905
+
906
+ # Run locally (HTTP)
907
+ MCP_TRANSPORT=http \
908
+ MCP_AUTH_TOKEN=dev-token \
909
+ WP_API_URL="https://your-site.com" \
910
+ WP_API_USERNAME="user" \
911
+ WP_API_PASSWORD="xxxx xxxx xxxx xxxx" \
912
+ node index.js
913
+
914
+ # Build MCPB bundle
915
+ npm run build:mcpb
669
916
  ```
670
917
 
671
918
  ### Testing with MCP Inspector
672
-
673
919
  ```bash
674
920
  npx @modelcontextprotocol/inspector node index.js
675
921
  ```
@@ -678,15 +924,137 @@ npx @modelcontextprotocol/inspector node index.js
678
924
 
679
925
  ## Changelog
680
926
 
927
+ ### v4.4.0 (2026-02-21) — Content Intelligence
928
+
929
+ 16 new read-only analysis tools for deep content intelligence without any WordPress plugin.
930
+
931
+ **Foundations:**
932
+ - `src/contentAnalyzer.js` — shared analysis engine: readability (Flesch-Kincaid FR), TF-IDF, cosine similarity, entity extraction, text diff, content structure detection
933
+ - `wp_get_content_brief` — editorial brief aggregator (SEO + structure + links in 1 call)
934
+ - `wp_extract_post_outline` — H1-H6 outline extraction with category-level pattern analysis
935
+
936
+ **SEO Advanced:**
937
+ - `wp_audit_readability` — bulk Flesch-Kincaid FR scoring with transition word and passive voice analysis
938
+ - `wp_audit_update_frequency` — outdated content detection cross-referenced with SEO scores
939
+ - `wp_build_link_map` — internal link matrix with simplified PageRank scoring (0-100)
940
+
941
+ **Technical Quality:**
942
+ - `wp_audit_anchor_texts` — anchor text diversity audit: generic, over-optimized, image link detection
943
+ - `wp_audit_schema_markup` — JSON-LD schema.org detection and validation (Article, FAQ, HowTo, LocalBusiness)
944
+ - `wp_audit_content_structure` — editorial structure scoring (0-100): intro, conclusion, FAQ, TOC, lists, images
945
+
946
+ **Intelligence Advanced:**
947
+ - `wp_find_duplicate_content` — TF-IDF cosine similarity for near-duplicate detection with union-find clustering
948
+ - `wp_find_content_gaps` — taxonomy under-representation analysis (categories + tags)
949
+ - `wp_extract_faq_blocks` — FAQ inventory: JSON-LD, Gutenberg blocks, HTML patterns
950
+ - `wp_audit_cta_presence` — CTA detection (6 types) with scoring 0-100
951
+ - `wp_extract_entities` — regex/heuristic named entity extraction (brands, locations, persons, organizations)
952
+ - `wp_get_publishing_velocity` — publication cadence by author/category with trend detection
953
+ - `wp_compare_revisions_diff` — textual diff between revisions with amplitude scoring
954
+ - `wp_list_posts_by_word_count` — posts sorted by length with 6-tier segmentation
955
+
956
+ All Content Intelligence tools are read-only and always allowed regardless of governance flags.
957
+
958
+ 613 Vitest unit tests · 79 tools
959
+
960
+ ### v4.2.0 (2026-02-19) — SEO Audit Suite (Sprint 3)
961
+
962
+ - `wp_find_broken_internal_links` — HEAD request link checker with configurable batch size and timeout. Returns broken (4xx/5xx), redirected (3xx), and slow links
963
+ - `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
964
+ - `wp_audit_taxonomies` — taxonomy bloat detection: unused terms, near-duplicate detection via Levenshtein distance, single-post terms, over-tagged posts
965
+ - `wp_audit_outbound_links` — external link profile per post: low-authority domains, missing rel="nofollow", broken external URLs
966
+ - `src/htmlParser.js` — shared HTML parsing service (parseImagesFromHtml, extractHeadings, extractInternalLinks, countWords)
967
+ - 400 Vitest unit tests · 63 tools
968
+
969
+ ### v4.1.0 (2026-02-19) — SEO Audit Suite (Sprint 2)
970
+
971
+ - `wp_find_thin_content` — surface posts below configurable word count threshold. Scores content quality by word count, heading density, and paragraph structure
972
+ - `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
973
+ - `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
974
+ - 368 Vitest unit tests · 59 tools
975
+
976
+ ### v4.0.0 (2026-02-19) — SEO Audit Suite (Sprint 1)
977
+
978
+ - `wp_audit_media_seo` — audit media library for missing alt text, short alt text, unoptimized filenames. Returns per-image scores and prioritized fix list
979
+ - `wp_find_orphan_pages` — identify posts with no internal links pointing to them, sorted by word count. Configurable minimum word threshold and exclusion list
980
+ - `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
981
+ - All 10 SEO audit tools are read-only and always allowed regardless of governance flags
982
+ - 340 Vitest unit tests · 56 tools
983
+
984
+ ### v3.6.0 (2026-02-19) — WooCommerce Write
985
+
986
+ - `wc_update_product` — update product fields (title, description, price, stock, status). Integrated with `wc_price_guardrail` threshold enforcement
987
+ - `wc_update_order_status` — transition order status (e.g., processing → completed)
988
+ - `WC_PRICE_GUARDRAIL_THRESHOLD` — configurable price change safety threshold (default 20%)
989
+ - All WooCommerce write tools blocked by `WP_READ_ONLY`
990
+ - 305 Vitest unit tests · 53 tools
991
+
992
+ ### v3.5.0 (2026-02-19) — WooCommerce Intelligence
993
+
994
+ - `wc_get_customer` — customer profile with order history summary and lifetime value
995
+ - `wc_list_coupons` / `wc_get_coupon` — coupon management with discount rules and usage stats
996
+ - `wc_sales_report` — revenue, orders, and average order value for a date range
997
+ - `wc_top_products` — ranking by revenue, quantity sold, or order count
998
+ - 287 Vitest unit tests · 50 tools
999
+
1000
+ ### v3.4.0 (2026-02-19) — WooCommerce Core
1001
+
1002
+ - `wc_list_products` / `wc_get_product` — product catalog with variation support
1003
+ - `wc_list_orders` / `wc_get_order` — order management with full line item detail
1004
+ - `wc_list_customers` — customer list with search and role filtering
1005
+ - `wc_price_guardrail` — read-only price change safety analysis
1006
+ - Requires `WC_CONSUMER_KEY` and `WC_CONSUMER_SECRET`
1007
+ - 271 Vitest unit tests · 46 tools
1008
+
1009
+ ### v3.3.0 (2026-02-19) — Internal Link Intelligence
1010
+
1011
+ - `wp_analyze_links` — audit all internal/external links in a post. HEAD request verification per link (broken/warning/unknown). Max 20 checks, configurable timeout
1012
+ - `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
1013
+ - `src/linkUtils.js` — 6 shared utilities: extractInternalLinks, extractExternalLinks, checkLinkStatus, extractFocusKeyword (auto-detects RankMath/Yoast/SEOPress/AIOSEO), calculateRelevanceScore, suggestAnchorText
1014
+ - Pre-flight linking workflow: suggest → user validates → `wp_update_post` (never auto-insert)
1015
+ - 253 Vitest unit tests · 40 tools
1016
+
1017
+ ### v3.2.0 (2026-02-19) — Governance Workflows
1018
+
1019
+ - Editorial approval workflow: `wp_submit_for_review` (draft → pending), `wp_approve_post` (pending → publish), `wp_reject_post` (pending → draft + mandatory reason)
1020
+ - New governance flag: `WP_REQUIRE_APPROVAL` — blocks direct publish, forces approval workflow
1021
+ - 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`
1022
+ - New governance flag: `WP_CONFIRM_DESTRUCTIVE` — requires explicit token confirmation before any delete
1023
+ - `src/confirmationToken.js` — stateless token system, zero persistence
1024
+ - Governance priority: `WP_READ_ONLY` → `WP_DISABLE_DELETE` → `WP_CONFIRM_DESTRUCTIVE`
1025
+ - 225 Vitest unit tests · 38 tools
1026
+
1027
+ ### v3.1.0 (2026-02-19) — MCPB Bundle
1028
+
1029
+ - `dxt/manifest.json` — MCPB v0.3 spec, 35 tools declared
1030
+ - WordPress credentials stored in OS keychain (`sensitive: true`)
1031
+ - `npm run build:mcpb` — build script for `.mcpb` distribution
1032
+ - 10 new manifest validation tests (201 total)
1033
+ - Published to npm: `npx -y @adsim/wordpress-mcp-server@3.1.0`
1034
+
1035
+ ### v3.0.0 (2026-02-19) — HTTP Streamable Transport
1036
+
1037
+ - HTTP Streamable transport (MCP spec 2025-03-26) via `MCP_TRANSPORT=http`
1038
+ - Bearer token authentication with timing-safe comparison (`MCP_AUTH_TOKEN`)
1039
+ - Session management via `Mcp-Session-Id` header (UUID v4)
1040
+ - Origin header validation (anti-DNS-rebinding)
1041
+ - Health endpoint `GET /health`
1042
+ - Dual mode `MCP_DUAL_MODE=true` — stdio + HTTP simultaneously
1043
+ - Graceful shutdown SIGTERM/SIGINT across both transports
1044
+ - 10 new HTTP/auth unit tests (191 total)
1045
+ - Published to npm: `@adsim/wordpress-mcp-server`
1046
+
681
1047
  ### 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
1048
+
1049
+ - 9 new tools: plugins (list/activate/deactivate), themes (list/get), revisions (list/get/restore/delete)
1050
+ - New governance flag: `WP_DISABLE_PLUGIN_MANAGEMENT`
1051
+ - 171 Vitest unit tests covering all 35 tools (governance, success, 403/404, audit logs)
1052
+ - GitHub Actions CI workflow
686
1053
  - Governance functions read env at call time for testability
687
1054
  - Exported `handleToolCall` for direct testing
688
1055
 
689
1056
  ### v2.1.0 (2026-02-16)
1057
+
690
1058
  - Enterprise governance controls (read-only, draft-only, type/status allowlists)
691
1059
  - Structured JSON audit trail (27 instrumentation points)
692
1060
  - Multi-target site management
@@ -695,26 +1063,25 @@ npx @modelcontextprotocol/inspector node index.js
695
1063
  - Health checks, retry with backoff, rate limiting
696
1064
 
697
1065
  ### v1.0.0 (2025-10-17)
1066
+
698
1067
  - Initial release — JavaScript, 5 tools (list, get, create, update, search posts)
699
1068
 
700
1069
  ---
701
1070
 
702
1071
  ## Roadmap
703
1072
 
704
- ### v2.3Governance Workflows
705
- - Approval workflow: draft human review publish
706
- - Confirmation step for destructive actions
707
- - Per-target enterprise controls
1073
+ ### v4.5GSC Integration
1074
+ - `wp_get_gsc_performance` Google Search Console API (clicks, impressions, position, CTR per URL)
1075
+ - `wp_find_quick_win_keywords` surface keywords ranking positions 11–20 for targeted updates
1076
+ - `wp_seo_content_decay` — cross-reference GSC traffic loss with content age to prioritize refresh candidates
708
1077
 
709
- ### v2.4Extended Integrations
710
- - OAuth 2.0 / JWT authentication
711
- - WooCommerce support (products, orders)
712
- - Media management (bulk, transforms)
1078
+ ### v4.6Redirect Intelligence
1079
+ - `wp_create_redirect` create 301 redirects via Redirection plugin or RankMath/Yoast Redirects. Auto-triggered governance hook when `wp_update_post` changes a slug
1080
+ - `wp_list_404_errors` surface recent 404s from Redirection plugin log
713
1081
 
714
- ### v2.5Distribution
715
- - npm: `npx @adsim/wordpress-mcp-server`
1082
+ ### v4.7OAuth & Registry
1083
+ - OAuth 2.0 / JWT authentication
716
1084
  - MCP Registry submission
717
- - TypeScript rewrite
718
1085
 
719
1086
  ---
720
1087