@adsim/wordpress-mcp-server 1.0.0 → 3.0.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.
- package/.env.example +8 -0
- package/.github/workflows/ci.yml +20 -0
- package/LICENSE +1 -1
- package/README.md +596 -135
- package/index.js +1367 -0
- package/package.json +21 -33
- package/src/auth/bearer.js +72 -0
- package/src/transport/http.js +264 -0
- package/tests/helpers/mockWpRequest.js +135 -0
- package/tests/unit/governance.test.js +260 -0
- package/tests/unit/tools/comments.test.js +170 -0
- package/tests/unit/tools/media.test.js +279 -0
- package/tests/unit/tools/pages.test.js +222 -0
- package/tests/unit/tools/plugins.test.js +268 -0
- package/tests/unit/tools/posts.test.js +310 -0
- package/tests/unit/tools/revisions.test.js +299 -0
- package/tests/unit/tools/search.test.js +190 -0
- package/tests/unit/tools/seo.test.js +248 -0
- package/tests/unit/tools/site.test.js +133 -0
- package/tests/unit/tools/taxonomies.test.js +220 -0
- package/tests/unit/tools/themes.test.js +163 -0
- package/tests/unit/tools/users.test.js +113 -0
- package/tests/unit/transport/http.test.js +300 -0
- package/vitest.config.js +12 -0
- package/dist/constants.d.ts +0 -13
- package/dist/constants.d.ts.map +0 -1
- package/dist/constants.js +0 -10
- package/dist/constants.js.map +0 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -33
- package/dist/index.js.map +0 -1
- package/dist/schemas/index.d.ts +0 -308
- package/dist/schemas/index.d.ts.map +0 -1
- package/dist/schemas/index.js +0 -191
- package/dist/schemas/index.js.map +0 -1
- package/dist/services/formatters.d.ts +0 -22
- package/dist/services/formatters.d.ts.map +0 -1
- package/dist/services/formatters.js +0 -52
- package/dist/services/formatters.js.map +0 -1
- package/dist/services/wp-client.d.ts +0 -38
- package/dist/services/wp-client.d.ts.map +0 -1
- package/dist/services/wp-client.js +0 -102
- package/dist/services/wp-client.js.map +0 -1
- package/dist/tools/content.d.ts +0 -4
- package/dist/tools/content.d.ts.map +0 -1
- package/dist/tools/content.js +0 -196
- package/dist/tools/content.js.map +0 -1
- package/dist/tools/posts.d.ts +0 -4
- package/dist/tools/posts.d.ts.map +0 -1
- package/dist/tools/posts.js +0 -179
- package/dist/tools/posts.js.map +0 -1
- package/dist/tools/seo.d.ts +0 -4
- package/dist/tools/seo.d.ts.map +0 -1
- package/dist/tools/seo.js +0 -241
- package/dist/tools/seo.js.map +0 -1
- package/dist/tools/taxonomy.d.ts +0 -4
- package/dist/tools/taxonomy.d.ts.map +0 -1
- package/dist/tools/taxonomy.js +0 -82
- package/dist/tools/taxonomy.js.map +0 -1
- package/dist/types.d.ts +0 -160
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -3
- package/dist/types.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,53 +1,109 @@
|
|
|
1
1
|
# WordPress MCP Server
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/@adsim/wordpress-mcp-server)
|
|
4
3
|
[](https://opensource.org/licenses/MIT)
|
|
4
|
+
[](https://nodejs.org/)
|
|
5
|
+
[](https://modelcontextprotocol.io/)
|
|
6
|
+
[]()
|
|
5
7
|
|
|
6
|
-
|
|
8
|
+
Enterprise Governance · Audit Trail · Multi-Site · Plugin-Free
|
|
7
9
|
|
|
8
|
-
|
|
10
|
+
The enterprise governance layer for Claude-to-WordPress integrations — secure, auditable, and multi-site.
|
|
11
|
+
|
|
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**
|
|
9
13
|
|
|
10
14
|
---
|
|
11
15
|
|
|
12
|
-
##
|
|
16
|
+
## Architecture
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
┌─────────────────────────┐
|
|
20
|
+
│ Claude Client │ Claude Desktop · Claude Code · Any MCP client
|
|
21
|
+
└────────────┬────────────┘
|
|
22
|
+
│ MCP Protocol (stdio)
|
|
23
|
+
┌────────────▼────────────┐
|
|
24
|
+
│ WordPress MCP Server │ Node.js · Standalone · No WordPress plugin
|
|
25
|
+
├─────────────────────────┤
|
|
26
|
+
│ Execution Controls │ Read-only · Draft-only · Plugin mgmt · Type/status allowlists
|
|
27
|
+
├─────────────────────────┤
|
|
28
|
+
│ Audit Logging │ JSON on stderr · 35 instrumentation points
|
|
29
|
+
├─────────────────────────┤
|
|
30
|
+
│ Rate Limiting │ Client-side · Configurable per-minute cap
|
|
31
|
+
└────────────┬────────────┘
|
|
32
|
+
│ HTTPS + WordPress Application Password (Basic Auth over TLS)
|
|
33
|
+
┌────────────▼────────────┐
|
|
34
|
+
│ WordPress REST API │ Single site or multi-target
|
|
35
|
+
└─────────────────────────┘
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Why This Server
|
|
39
|
+
|
|
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.
|
|
41
|
+
|
|
42
|
+
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
|
+
|
|
44
|
+
No composer, no PHP build, no WordPress admin plugin. Point it at any WordPress site with an Application Password, configure your execution policy, and connect your Claude client.
|
|
45
|
+
|
|
46
|
+
## Safety Model
|
|
47
|
+
|
|
48
|
+
This server is designed for safe operation in production environments:
|
|
49
|
+
|
|
50
|
+
- **Default non-destructive** — delete operations must be explicitly enabled
|
|
51
|
+
- **Configurable execution modes** — read-only, draft-only, or full access per deployment
|
|
52
|
+
- **Pre-flight enforcement** — all guardrails checked before any API call is made
|
|
53
|
+
- **Full audit trail** — every action logged with timestamp, target, outcome, and latency
|
|
54
|
+
- **Credential isolation** — secrets never appear in logs or error outputs
|
|
55
|
+
- **Multi-tenant ready** — independent auth and config per WordPress target
|
|
13
56
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
| **Pages** | `wp_list_pages` | List and filter pages |
|
|
18
|
-
| **Taxonomy** | `wp_list_categories`, `wp_list_tags` | Browse categories and tags |
|
|
19
|
-
| **SEO** | `wp_get_seo_meta`, `wp_update_seo_meta`, `wp_audit_seo` | RankMath & Yoast support, SEO auditing with scoring |
|
|
20
|
-
| **Media** | `wp_list_media` | Browse media library by type |
|
|
21
|
-
| **Search** | `wp_search` | Cross-content search |
|
|
22
|
-
| **Users** | `wp_list_users` | List users by role |
|
|
23
|
-
| **Comments** | `wp_list_comments` | List and filter comments |
|
|
24
|
-
| **Site** | `wp_site_info` | Get site name, URL, timezone |
|
|
57
|
+
## Data Retention
|
|
58
|
+
|
|
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.
|
|
25
60
|
|
|
26
61
|
---
|
|
27
62
|
|
|
28
63
|
## Quick Start
|
|
29
64
|
|
|
30
|
-
###
|
|
65
|
+
### Requirements
|
|
66
|
+
|
|
67
|
+
- Node.js >= 18
|
|
68
|
+
- WordPress site with REST API enabled (default since WP 4.7)
|
|
69
|
+
- WordPress Application Password (WP 5.6+)
|
|
70
|
+
- HTTPS endpoint (required for production)
|
|
71
|
+
|
|
72
|
+
### Install
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
git clone https://github.com/GeorgesAdSim/wordpress-mcp-server.git
|
|
76
|
+
cd wordpress-mcp-server
|
|
77
|
+
npm install
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Configure
|
|
31
81
|
|
|
32
|
-
|
|
33
|
-
- **WordPress site** with REST API enabled (enabled by default)
|
|
34
|
-
- **Application Password** (WordPress → Users → Your Profile → Application Passwords)
|
|
82
|
+
Create a `.env` file:
|
|
35
83
|
|
|
36
|
-
|
|
84
|
+
```bash
|
|
85
|
+
WP_API_URL=https://yoursite.com
|
|
86
|
+
WP_API_USERNAME=your-username
|
|
87
|
+
WP_API_PASSWORD=xxxx xxxx xxxx xxxx xxxx xxxx
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
To generate an Application Password: WordPress Admin → Users → Profile → Application Passwords → Add New.
|
|
37
91
|
|
|
38
|
-
|
|
92
|
+
### Connect to Claude Desktop
|
|
39
93
|
|
|
40
|
-
|
|
41
|
-
|
|
94
|
+
Add to `claude_desktop_config.json`:
|
|
95
|
+
|
|
96
|
+
**macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
97
|
+
**Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
|
42
98
|
|
|
43
99
|
```json
|
|
44
100
|
{
|
|
45
101
|
"mcpServers": {
|
|
46
102
|
"wordpress": {
|
|
47
|
-
"command": "
|
|
48
|
-
"args": ["
|
|
103
|
+
"command": "node",
|
|
104
|
+
"args": ["/path/to/wordpress-mcp-server/index.js"],
|
|
49
105
|
"env": {
|
|
50
|
-
"WP_API_URL": "https://
|
|
106
|
+
"WP_API_URL": "https://yoursite.com",
|
|
51
107
|
"WP_API_USERNAME": "your-username",
|
|
52
108
|
"WP_API_PASSWORD": "xxxx xxxx xxxx xxxx xxxx xxxx"
|
|
53
109
|
}
|
|
@@ -56,166 +112,539 @@ Add to your Claude Desktop config file:
|
|
|
56
112
|
}
|
|
57
113
|
```
|
|
58
114
|
|
|
59
|
-
###
|
|
115
|
+
### Connect to Claude Code
|
|
60
116
|
|
|
61
|
-
|
|
117
|
+
```bash
|
|
118
|
+
claude mcp add wordpress \
|
|
119
|
+
-e WP_API_URL=https://yoursite.com \
|
|
120
|
+
-e WP_API_USERNAME=your-username \
|
|
121
|
+
-e WP_API_PASSWORD="xxxx xxxx xxxx xxxx xxxx xxxx" \
|
|
122
|
+
-- node /path/to/wordpress-mcp-server/index.js
|
|
123
|
+
```
|
|
62
124
|
|
|
63
125
|
---
|
|
64
126
|
|
|
65
|
-
##
|
|
127
|
+
## Available Tools (35)
|
|
128
|
+
|
|
129
|
+
### Content Management
|
|
130
|
+
|
|
131
|
+
| 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 |
|
|
143
|
+
|
|
144
|
+
### Media Library
|
|
145
|
+
|
|
146
|
+
| 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 |
|
|
151
|
+
|
|
152
|
+
### Taxonomies & Structure
|
|
153
|
+
|
|
154
|
+
| 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) |
|
|
161
|
+
|
|
162
|
+
### Engagement
|
|
163
|
+
|
|
164
|
+
| 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) |
|
|
169
|
+
|
|
170
|
+
### SEO Metadata
|
|
171
|
+
|
|
172
|
+
| 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 |
|
|
177
|
+
|
|
178
|
+
SEO metadata updates are subject to the same enterprise controls and execution policies as all other write operations.
|
|
179
|
+
|
|
180
|
+
### Plugins
|
|
181
|
+
|
|
182
|
+
| 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` |
|
|
187
|
+
|
|
188
|
+
### Themes
|
|
189
|
+
|
|
190
|
+
| 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 |
|
|
66
194
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
|
70
|
-
|
|
71
|
-
|
|
|
195
|
+
### Revisions
|
|
196
|
+
|
|
197
|
+
| 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` |
|
|
203
|
+
|
|
204
|
+
### Operations
|
|
205
|
+
|
|
206
|
+
| 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 |
|
|
72
210
|
|
|
73
211
|
---
|
|
74
212
|
|
|
75
|
-
##
|
|
213
|
+
## Enterprise Controls
|
|
76
214
|
|
|
77
|
-
|
|
215
|
+
Configure execution policy via environment variables. All restrictions are enforced before any API call is made — including SEO metadata and plugin operations.
|
|
78
216
|
|
|
79
|
-
|
|
80
|
-
|
|
217
|
+
| 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 |
|
|
81
227
|
|
|
82
|
-
###
|
|
228
|
+
### Deployment profiles
|
|
229
|
+
|
|
230
|
+
**Agency content production** — writers can create and edit, but never publish or delete:
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
WP_DRAFT_ONLY=true
|
|
234
|
+
WP_DISABLE_DELETE=true
|
|
235
|
+
WP_ALLOWED_STATUSES=draft,pending
|
|
236
|
+
WP_MAX_CALLS_PER_MINUTE=30
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
**Compliance monitoring** — read-only access for auditing existing content:
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
WP_READ_ONLY=true
|
|
243
|
+
WP_AUDIT_LOG=on
|
|
244
|
+
```
|
|
83
245
|
|
|
84
|
-
|
|
246
|
+
**Regulated publishing** — restrict to specific content types in a controlled environment:
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
WP_ALLOWED_TYPES=post
|
|
250
|
+
WP_ALLOWED_STATUSES=draft,pending,publish
|
|
251
|
+
WP_DISABLE_DELETE=true
|
|
252
|
+
WP_AUDIT_LOG=on
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
**Locked infrastructure** — content operations allowed, but no plugin/theme changes:
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
WP_DISABLE_PLUGIN_MANAGEMENT=true
|
|
259
|
+
WP_DISABLE_DELETE=true
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Blocked actions return a clear error message explaining which control prevented execution, and are logged in the audit trail with status `blocked`.
|
|
263
|
+
|
|
264
|
+
---
|
|
85
265
|
|
|
86
|
-
|
|
266
|
+
## SEO Metadata
|
|
267
|
+
|
|
268
|
+
The SEO tools auto-detect which SEO plugin is installed on your WordPress site and use the correct meta fields automatically.
|
|
269
|
+
|
|
270
|
+
Supported plugins:
|
|
271
|
+
|
|
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
|
|
276
|
+
|
|
277
|
+
### SEO Audit Scoring
|
|
278
|
+
|
|
279
|
+
`wp_audit_seo` scores each post on a 100-point scale:
|
|
280
|
+
|
|
281
|
+
| Check | Penalty |
|
|
282
|
+
|-------|---------|
|
|
283
|
+
| Missing SEO title | -30 |
|
|
284
|
+
| SEO title too short (< 30 chars) or too long (> 60 chars) | -10 |
|
|
285
|
+
| Missing meta description | -30 |
|
|
286
|
+
| Meta description too short (< 120 chars) or too long (> 160 chars) | -10 |
|
|
287
|
+
| Missing focus keyword | -20 |
|
|
288
|
+
| Focus keyword not in SEO title | -10 |
|
|
289
|
+
|
|
290
|
+
### Exposing SEO Meta Fields (Required)
|
|
291
|
+
|
|
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.
|
|
293
|
+
|
|
294
|
+
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
|
+
|
|
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.
|
|
297
|
+
|
|
298
|
+
**RankMath:**
|
|
87
299
|
|
|
88
300
|
```php
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
add_action('init', function() {
|
|
92
|
-
$fields = [
|
|
301
|
+
add_action( 'init', function() {
|
|
302
|
+
$fields = array(
|
|
93
303
|
'rank_math_title',
|
|
94
304
|
'rank_math_description',
|
|
95
305
|
'rank_math_focus_keyword',
|
|
306
|
+
'rank_math_canonical_url',
|
|
96
307
|
'rank_math_robots',
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
308
|
+
'rank_math_facebook_title',
|
|
309
|
+
'rank_math_facebook_description',
|
|
310
|
+
'rank_math_facebook_image',
|
|
311
|
+
);
|
|
312
|
+
foreach ( $fields as $field ) {
|
|
313
|
+
foreach ( array( 'post', 'page' ) as $post_type ) {
|
|
314
|
+
register_post_meta( $post_type, $field, array(
|
|
315
|
+
'show_in_rest' => true,
|
|
316
|
+
'single' => true,
|
|
317
|
+
'type' => 'string',
|
|
318
|
+
'auth_callback' => function() {
|
|
319
|
+
return current_user_can( 'edit_posts' );
|
|
320
|
+
},
|
|
321
|
+
) );
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
} );
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
**Yoast SEO:**
|
|
328
|
+
|
|
329
|
+
```php
|
|
330
|
+
add_action( 'init', function() {
|
|
331
|
+
$fields = array(
|
|
332
|
+
'_yoast_wpseo_title',
|
|
333
|
+
'_yoast_wpseo_metadesc',
|
|
334
|
+
'_yoast_wpseo_focuskw',
|
|
335
|
+
'_yoast_wpseo_canonical',
|
|
336
|
+
'_yoast_wpseo_meta-robots-noindex',
|
|
337
|
+
'_yoast_wpseo_meta-robots-nofollow',
|
|
338
|
+
'_yoast_wpseo_opengraph-title',
|
|
339
|
+
'_yoast_wpseo_opengraph-description',
|
|
340
|
+
'_yoast_wpseo_opengraph-image',
|
|
341
|
+
);
|
|
342
|
+
foreach ( $fields as $field ) {
|
|
343
|
+
foreach ( array( 'post', 'page' ) as $post_type ) {
|
|
344
|
+
register_post_meta( $post_type, $field, array(
|
|
345
|
+
'show_in_rest' => true,
|
|
346
|
+
'single' => true,
|
|
347
|
+
'type' => 'string',
|
|
348
|
+
'auth_callback' => function() {
|
|
349
|
+
return current_user_can( 'edit_posts' );
|
|
350
|
+
},
|
|
351
|
+
) );
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
} );
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
**SEOPress:**
|
|
358
|
+
|
|
359
|
+
```php
|
|
360
|
+
add_action( 'init', function() {
|
|
361
|
+
$fields = array(
|
|
362
|
+
'_seopress_titles_title',
|
|
363
|
+
'_seopress_titles_desc',
|
|
364
|
+
'_seopress_analysis_target_kw',
|
|
365
|
+
'_seopress_robots_canonical',
|
|
366
|
+
'_seopress_robots_index',
|
|
367
|
+
'_seopress_social_fb_title',
|
|
368
|
+
'_seopress_social_fb_desc',
|
|
369
|
+
'_seopress_social_fb_img',
|
|
370
|
+
);
|
|
371
|
+
foreach ( $fields as $field ) {
|
|
372
|
+
foreach ( array( 'post', 'page' ) as $post_type ) {
|
|
373
|
+
register_post_meta( $post_type, $field, array(
|
|
374
|
+
'show_in_rest' => true,
|
|
375
|
+
'single' => true,
|
|
376
|
+
'type' => 'string',
|
|
377
|
+
'auth_callback' => function() {
|
|
378
|
+
return current_user_can( 'edit_posts' );
|
|
379
|
+
},
|
|
380
|
+
) );
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
} );
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
**All in One SEO:**
|
|
387
|
+
|
|
388
|
+
```php
|
|
389
|
+
add_action( 'init', function() {
|
|
390
|
+
$fields = array(
|
|
391
|
+
'_aioseo_title',
|
|
392
|
+
'_aioseo_description',
|
|
393
|
+
'_aioseo_keywords',
|
|
394
|
+
'_aioseo_og_title',
|
|
395
|
+
'_aioseo_og_description',
|
|
396
|
+
'_aioseo_og_image_url',
|
|
397
|
+
);
|
|
398
|
+
foreach ( $fields as $field ) {
|
|
399
|
+
foreach ( array( 'post', 'page' ) as $post_type ) {
|
|
400
|
+
register_post_meta( $post_type, $field, array(
|
|
102
401
|
'show_in_rest' => true,
|
|
103
402
|
'single' => true,
|
|
104
403
|
'type' => 'string',
|
|
105
404
|
'auth_callback' => function() {
|
|
106
|
-
return current_user_can('edit_posts');
|
|
405
|
+
return current_user_can( 'edit_posts' );
|
|
107
406
|
},
|
|
108
|
-
|
|
407
|
+
) );
|
|
109
408
|
}
|
|
110
409
|
}
|
|
111
|
-
});
|
|
410
|
+
} );
|
|
112
411
|
```
|
|
113
412
|
|
|
114
|
-
|
|
413
|
+
### Alternative: MCP SEO Bridge Plugin (Recommended)
|
|
115
414
|
|
|
116
|
-
|
|
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.
|
|
117
416
|
|
|
118
|
-
|
|
417
|
+
Instead of modifying your theme's `functions.php` (which gets overwritten on theme updates), create a standalone micro-plugin.
|
|
119
418
|
|
|
120
|
-
|
|
419
|
+
Create the file `wp-content/plugins/mcp-seo-bridge.php`:
|
|
121
420
|
|
|
122
421
|
```php
|
|
123
422
|
<?php
|
|
124
423
|
/**
|
|
125
424
|
* Plugin Name: MCP SEO Bridge
|
|
126
|
-
* Description: Exposes SEO meta fields for MCP
|
|
425
|
+
* Description: Exposes SEO plugin meta fields via REST API for WordPress MCP Server
|
|
127
426
|
* Version: 1.0.0
|
|
427
|
+
* Author: AdSim
|
|
428
|
+
* Author URI: https://adsim.be
|
|
128
429
|
*/
|
|
129
430
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
431
|
+
if ( ! defined( 'ABSPATH' ) ) exit;
|
|
432
|
+
|
|
433
|
+
add_action( 'init', function() {
|
|
434
|
+
// Auto-detect SEO plugin and register appropriate fields
|
|
435
|
+
$fields = array();
|
|
436
|
+
|
|
437
|
+
if ( defined( 'RANK_MATH_VERSION' ) ) {
|
|
438
|
+
$fields = array(
|
|
439
|
+
'rank_math_title', 'rank_math_description', 'rank_math_focus_keyword',
|
|
440
|
+
'rank_math_canonical_url', 'rank_math_robots',
|
|
441
|
+
'rank_math_facebook_title', 'rank_math_facebook_description', 'rank_math_facebook_image',
|
|
442
|
+
);
|
|
443
|
+
} elseif ( defined( 'WPSEO_VERSION' ) ) {
|
|
444
|
+
$fields = array(
|
|
445
|
+
'_yoast_wpseo_title', '_yoast_wpseo_metadesc', '_yoast_wpseo_focuskw',
|
|
446
|
+
'_yoast_wpseo_canonical', '_yoast_wpseo_meta-robots-noindex', '_yoast_wpseo_meta-robots-nofollow',
|
|
447
|
+
'_yoast_wpseo_opengraph-title', '_yoast_wpseo_opengraph-description', '_yoast_wpseo_opengraph-image',
|
|
448
|
+
);
|
|
449
|
+
} elseif ( defined( 'SEOPRESS_VERSION' ) ) {
|
|
450
|
+
$fields = array(
|
|
451
|
+
'_seopress_titles_title', '_seopress_titles_desc', '_seopress_analysis_target_kw',
|
|
452
|
+
'_seopress_robots_canonical', '_seopress_robots_index',
|
|
453
|
+
'_seopress_social_fb_title', '_seopress_social_fb_desc', '_seopress_social_fb_img',
|
|
454
|
+
);
|
|
455
|
+
} elseif ( defined( 'AIOSEO_VERSION' ) ) {
|
|
456
|
+
$fields = array(
|
|
457
|
+
'_aioseo_title', '_aioseo_description', '_aioseo_keywords',
|
|
458
|
+
'_aioseo_og_title', '_aioseo_og_description', '_aioseo_og_image_url',
|
|
459
|
+
);
|
|
139
460
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
461
|
+
|
|
462
|
+
foreach ( $fields as $field ) {
|
|
463
|
+
foreach ( array( 'post', 'page' ) as $post_type ) {
|
|
464
|
+
register_post_meta( $post_type, $field, array(
|
|
465
|
+
'show_in_rest' => true,
|
|
466
|
+
'single' => true,
|
|
467
|
+
'type' => 'string',
|
|
468
|
+
'auth_callback' => function() {
|
|
469
|
+
return current_user_can( 'edit_posts' );
|
|
470
|
+
},
|
|
471
|
+
) );
|
|
148
472
|
}
|
|
149
473
|
}
|
|
150
|
-
});
|
|
474
|
+
} );
|
|
151
475
|
```
|
|
152
476
|
|
|
153
|
-
|
|
477
|
+
Activate it from WordPress Admin → Plugins. This approach auto-detects your SEO plugin and survives theme updates.
|
|
478
|
+
|
|
479
|
+
### Verifying SEO Fields Are Exposed
|
|
480
|
+
|
|
481
|
+
After adding the code, verify the fields are accessible:
|
|
482
|
+
|
|
483
|
+
```bash
|
|
484
|
+
curl -s -u "username:application-password" \
|
|
485
|
+
"https://yoursite.com/wp-json/wp/v2/posts?per_page=1" | python3 -m json.tool | grep -E "rank_math|yoast|seopress|aioseo"
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
If you see your SEO fields in the meta object, the configuration is working.
|
|
489
|
+
|
|
490
|
+
### Troubleshooting SEO Fields
|
|
491
|
+
|
|
492
|
+
| 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` |
|
|
496
|
+
| SEO fields visible but all null | SEO plugin not yet configured on those posts | Set titles/descriptions in RankMath/Yoast editor |
|
|
497
|
+
| 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 |
|
|
154
499
|
|
|
155
500
|
---
|
|
156
501
|
|
|
157
|
-
##
|
|
502
|
+
## Testing
|
|
158
503
|
|
|
159
|
-
|
|
504
|
+
171 unit tests covering all 35 tools — zero network calls, fully mocked.
|
|
160
505
|
|
|
506
|
+
```bash
|
|
507
|
+
npm test # run all tests (vitest)
|
|
508
|
+
npm run test:watch # watch mode
|
|
509
|
+
npm run test:coverage # coverage report
|
|
161
510
|
```
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
511
|
+
|
|
512
|
+
| 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 |
|
|
527
|
+
|
|
528
|
+
Each test verifies: success response shape, governance blocking (write tools), HTTP error handling (403/404), and audit log entries.
|
|
529
|
+
|
|
530
|
+
---
|
|
531
|
+
|
|
532
|
+
## Structured Audit Log
|
|
533
|
+
|
|
534
|
+
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
|
+
```json
|
|
537
|
+
{
|
|
538
|
+
"timestamp": "2026-02-16T18:42:00.000Z",
|
|
539
|
+
"tool": "wp_create_post",
|
|
540
|
+
"target": 1234,
|
|
541
|
+
"target_type": "post",
|
|
542
|
+
"action": "create",
|
|
543
|
+
"status": "success",
|
|
544
|
+
"latency_ms": 245,
|
|
545
|
+
"site": "production",
|
|
546
|
+
"params": { "title": "New Post", "status": "draft" },
|
|
547
|
+
"error": null
|
|
548
|
+
}
|
|
169
549
|
```
|
|
170
550
|
|
|
551
|
+
35 instrumentation points across all tools. Three status types: `success`, `error`, `blocked`.
|
|
552
|
+
|
|
553
|
+
| 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 |
|
|
565
|
+
|
|
171
566
|
---
|
|
172
567
|
|
|
173
|
-
##
|
|
568
|
+
## Multi-Target
|
|
174
569
|
|
|
175
|
-
|
|
570
|
+
Manage multiple WordPress sites from a single server instance. Designed for agencies and multi-brand organizations.
|
|
176
571
|
|
|
177
|
-
|
|
178
|
-
List posts with advanced filtering.
|
|
572
|
+
**Inline configuration:**
|
|
179
573
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
| `page` | number | 1 | Page number |
|
|
184
|
-
| `status` | string | publish | publish/draft/pending/private/future/trash |
|
|
185
|
-
| `orderby` | string | date | date/id/title/slug/modified/author/relevance |
|
|
186
|
-
| `order` | string | desc | asc/desc |
|
|
187
|
-
| `categories` | string | — | Comma-separated category IDs |
|
|
188
|
-
| `tags` | string | — | Comma-separated tag IDs |
|
|
189
|
-
| `search` | string | — | Search keyword |
|
|
574
|
+
```bash
|
|
575
|
+
WP_TARGETS_JSON='{"production":{"url":"https://mysite.com","username":"admin","password":"xxxx"},"staging":{"url":"https://staging.mysite.com","username":"editor","password":"xxxx"}}'
|
|
576
|
+
```
|
|
190
577
|
|
|
191
|
-
|
|
192
|
-
Get full post data including SEO metadata.
|
|
578
|
+
**File-based configuration:**
|
|
193
579
|
|
|
194
|
-
|
|
195
|
-
|
|
580
|
+
```bash
|
|
581
|
+
WP_TARGETS_FILE=/path/to/targets.json
|
|
582
|
+
```
|
|
196
583
|
|
|
197
|
-
|
|
198
|
-
|
|
584
|
+
```json
|
|
585
|
+
{
|
|
586
|
+
"production": {
|
|
587
|
+
"url": "https://mysite.com",
|
|
588
|
+
"username": "admin",
|
|
589
|
+
"password": "xxxx xxxx xxxx xxxx xxxx xxxx"
|
|
590
|
+
},
|
|
591
|
+
"staging": {
|
|
592
|
+
"url": "https://staging.mysite.com",
|
|
593
|
+
"username": "editor",
|
|
594
|
+
"password": "xxxx xxxx xxxx xxxx xxxx xxxx"
|
|
595
|
+
},
|
|
596
|
+
"client-blog": {
|
|
597
|
+
"url": "https://client.com",
|
|
598
|
+
"username": "content-manager",
|
|
599
|
+
"password": "xxxx xxxx xxxx xxxx xxxx xxxx"
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
```
|
|
199
603
|
|
|
200
|
-
|
|
201
|
-
Delete or trash a post.
|
|
604
|
+
Switch targets during a session with `wp_set_target`. All available sites and the active target are visible in `wp_site_info`.
|
|
202
605
|
|
|
203
|
-
|
|
606
|
+
---
|
|
204
607
|
|
|
205
|
-
|
|
206
|
-
Read SEO metadata (RankMath/Yoast).
|
|
608
|
+
## Health & Reliability
|
|
207
609
|
|
|
208
|
-
|
|
209
|
-
Update RankMath SEO fields (title, description, focus keyword).
|
|
610
|
+
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.
|
|
210
611
|
|
|
211
|
-
|
|
212
|
-
|
|
612
|
+
| 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 |
|
|
213
617
|
|
|
214
|
-
|
|
618
|
+
---
|
|
215
619
|
|
|
216
|
-
|
|
620
|
+
## Security
|
|
217
621
|
|
|
218
|
-
|
|
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
|
|
628
|
+
|
|
629
|
+
---
|
|
630
|
+
|
|
631
|
+
## Troubleshooting
|
|
632
|
+
|
|
633
|
+
| 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 |
|
|
645
|
+
| 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) |
|
|
647
|
+
| Server not starting | Check Node.js 18+ is installed: `node --version` |
|
|
219
648
|
|
|
220
649
|
---
|
|
221
650
|
|
|
@@ -229,44 +658,76 @@ cd wordpress-mcp-server
|
|
|
229
658
|
# Install dependencies
|
|
230
659
|
npm install
|
|
231
660
|
|
|
232
|
-
#
|
|
233
|
-
npm
|
|
661
|
+
# Run tests
|
|
662
|
+
npm test
|
|
234
663
|
|
|
235
664
|
# Run locally
|
|
236
665
|
WP_API_URL="https://your-site.com" \
|
|
237
666
|
WP_API_USERNAME="user" \
|
|
238
667
|
WP_API_PASSWORD="xxxx xxxx xxxx xxxx" \
|
|
239
|
-
node
|
|
668
|
+
node index.js
|
|
240
669
|
```
|
|
241
670
|
|
|
242
671
|
### Testing with MCP Inspector
|
|
243
672
|
|
|
244
673
|
```bash
|
|
245
|
-
npx @modelcontextprotocol/inspector node
|
|
674
|
+
npx @modelcontextprotocol/inspector node index.js
|
|
246
675
|
```
|
|
247
676
|
|
|
248
677
|
---
|
|
249
678
|
|
|
250
|
-
##
|
|
679
|
+
## Changelog
|
|
251
680
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
681
|
+
### 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
|
|
686
|
+
- Governance functions read env at call time for testability
|
|
687
|
+
- Exported `handleToolCall` for direct testing
|
|
688
|
+
|
|
689
|
+
### v2.1.0 (2026-02-16)
|
|
690
|
+
- Enterprise governance controls (read-only, draft-only, type/status allowlists)
|
|
691
|
+
- Structured JSON audit trail (27 instrumentation points)
|
|
692
|
+
- Multi-target site management
|
|
693
|
+
- 27 MCP tools including pages CRUD, media upload, taxonomy creation, custom post types
|
|
694
|
+
- SEO auto-detection for 4 plugins (Yoast, RankMath, SEOPress, AIOSEO)
|
|
695
|
+
- Health checks, retry with backoff, rate limiting
|
|
696
|
+
|
|
697
|
+
### v1.0.0 (2025-10-17)
|
|
698
|
+
- Initial release — JavaScript, 5 tools (list, get, create, update, search posts)
|
|
260
699
|
|
|
261
700
|
---
|
|
262
701
|
|
|
263
|
-
##
|
|
702
|
+
## Roadmap
|
|
703
|
+
|
|
704
|
+
### v2.3 — Governance Workflows
|
|
705
|
+
- Approval workflow: draft → human review → publish
|
|
706
|
+
- Confirmation step for destructive actions
|
|
707
|
+
- Per-target enterprise controls
|
|
708
|
+
|
|
709
|
+
### v2.4 — Extended Integrations
|
|
710
|
+
- OAuth 2.0 / JWT authentication
|
|
711
|
+
- WooCommerce support (products, orders)
|
|
712
|
+
- Media management (bulk, transforms)
|
|
264
713
|
|
|
265
|
-
|
|
266
|
-
|
|
714
|
+
### v2.5 — Distribution
|
|
715
|
+
- npm: `npx @adsim/wordpress-mcp-server`
|
|
716
|
+
- MCP Registry submission
|
|
717
|
+
- TypeScript rewrite
|
|
267
718
|
|
|
268
719
|
---
|
|
269
720
|
|
|
721
|
+
## Contributing
|
|
722
|
+
|
|
723
|
+
Contributions welcome. Open an issue or submit a pull request.
|
|
724
|
+
|
|
270
725
|
## License
|
|
271
726
|
|
|
272
|
-
MIT
|
|
727
|
+
MIT — see [LICENSE](LICENSE).
|
|
728
|
+
|
|
729
|
+
## Credits
|
|
730
|
+
|
|
731
|
+
Built by [AdSim](https://adsim.be) — Digital Marketing & AI Agency, Liège, Belgium.
|
|
732
|
+
|
|
733
|
+
Building the governance layer for Claude-powered WordPress infrastructure in regulated environments.
|