@respira/wordpress-mcp-server 7.2.6 → 7.2.8
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/dist/server.d.ts +11 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +93 -4
- package/dist/server.js.map +1 -1
- package/dist/wordpress-client.d.ts.map +1 -1
- package/dist/wordpress-client.js +18 -4
- package/dist/wordpress-client.js.map +1 -1
- package/package.json +1 -1
package/dist/server.d.ts
CHANGED
|
@@ -149,6 +149,17 @@ export declare class RespiraWordPressServer {
|
|
|
149
149
|
* the plugin source (the first release tag that contains each route).
|
|
150
150
|
*/
|
|
151
151
|
private static readonly TOOL_MIN_PLUGIN_VERSION;
|
|
152
|
+
/**
|
|
153
|
+
* Capability negotiation Phase 2 (7.2.7): the feature flag each version-skewed
|
|
154
|
+
* tool needs. From plugin 7.4.20 the compatibility endpoint declares these
|
|
155
|
+
* flags from its LIVE registered REST routes, so this is an exact "does the
|
|
156
|
+
* route exist on this install" signal — more precise than the version map
|
|
157
|
+
* above and self-maintaining. The version map stays as the fallback for
|
|
158
|
+
* plugins older than 7.4.20, which do not declare per-capability features yet.
|
|
159
|
+
*/
|
|
160
|
+
private static readonly TOOL_REQUIRED_FEATURE;
|
|
161
|
+
/** First plugin version that declares per-capability features (Phase 2). */
|
|
162
|
+
private static readonly FEATURE_DECL_MIN_PLUGIN_VERSION;
|
|
152
163
|
/** True when version `a` is strictly older than `b` (both "x.y.z"). */
|
|
153
164
|
private static versionLt;
|
|
154
165
|
private filterToolsByContext;
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAoBH,OAAO,KAAK,EAAE,mBAAmB,EAAe,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAoBH,OAAO,KAAK,EAAE,mBAAmB,EAAe,MAAM,kBAAkB,CAAC;AAqTzE,qBAAa,sBAAsB;IACjC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,WAAW,CAAgC;IACnD,OAAO,CAAC,KAAK,CAA2C;IACxD,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,cAAc,CAAwB;IAC9C,OAAO,CAAC,YAAY,CAA4B;IAChD,8EAA8E;IAC9E,OAAO,CAAC,YAAY,CAA4B;IAChD,8EAA8E;IAC9E,OAAO,CAAC,mBAAmB,CAAS;IAEpC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAsB;IAEhE;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAWzB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;gBA4Bb,WAAW,EAAE,mBAAmB,EAAE,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE;IAsVvE,OAAO,CAAC,cAAc;IAItB;;;;;;;;;OASG;IACH,OAAO,CAAC,oBAAoB;IAkB5B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,aAAa;IA4BrB,gEAAgE;IAChE,OAAO,CAAC,aAAa;IAUrB;;;;;;OAMG;YACW,UAAU;IAgDxB;;;;;;;;;;;;;;OAcG;YACW,WAAW;IAiJzB;;;;;;;;;OASG;YACW,kBAAkB;IAiHhC;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,6BAA6B;IA0BrC;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,yBAAyB;IA+BjC,OAAO,CAAC,eAAe;IAmBvB,OAAO,CAAC,aAAa;YA2QP,kBAAkB;YA6BlB,yBAAyB;IASvC;;;OAGG;IACH,OAAO,CAAC,oBAAoB;YAyBd,QAAQ;IAuwFtB;;;;;;OAMG;IACH,yEAAyE;IACzE,OAAO,CAAC,mBAAmB,CAAoD;IAC/E,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAU;IAElD;;;;;;;;;OASG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,uBAAuB,CAQ7C;IAEF;;;;;;;OAOG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAQ3C;IAEF,4EAA4E;IAC5E,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,+BAA+B,CAAY;IAEnE,uEAAuE;IACvE,OAAO,CAAC,MAAM,CAAC,SAAS;YAWV,oBAAoB;YAqFpB,2BAA2B;IAazC;;;;OAIG;YACW,cAAc;IAY5B,OAAO,CAAC,mBAAmB;IAwT3B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAe3C;IAEF;;;;OAIG;IACH,OAAO,CAAC,0BAA0B;YAmCpB,cAAc;IAqG5B;;;;;;;;;;;;;;;;;;;OAmBG;IACH,OAAO,CAAC,eAAe;YAuCT,gBAAgB;IA22B9B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAwUzB;;OAEG;IACH,OAAO,CAAC,sBAAsB;IA6UxB,GAAG;CAyCV"}
|
package/dist/server.js
CHANGED
|
@@ -17,6 +17,58 @@ import { getBricksTools, dispatchBricksTool } from './bricks-tools.js';
|
|
|
17
17
|
import { getElementorTools, dispatchElementorTool } from './elementor-tools.js';
|
|
18
18
|
import { getAcfTools, ACF_TOOL_NAMES } from './acf-tools.js';
|
|
19
19
|
import { getUsageEmitter, deriveToolKind } from './usage-emitter.js';
|
|
20
|
+
/**
|
|
21
|
+
* Per-tool argument aliases. AI clients (especially Cowork / Claude desktop)
|
|
22
|
+
* frequently pass a natural-but-wrong key for a value: `pageId` / `page_id`
|
|
23
|
+
* instead of `id`, `filePath` instead of `file`. Because the dispatch never
|
|
24
|
+
* validated required params, a misnamed id silently produced a broken request
|
|
25
|
+
* like `/wp-json/respira/v2/pages/undefined`, and a misnamed file produced an
|
|
26
|
+
* empty upload that failed with "Could not connect — no response received".
|
|
27
|
+
*
|
|
28
|
+
* This map fills the canonical key a handler reads from the first present
|
|
29
|
+
* synonym, and ONLY when the canonical key is absent — an explicit value is
|
|
30
|
+
* never overwritten. Keyed by the canonical (wordpress_*) tool name, i.e.
|
|
31
|
+
* after normalizeToolName().
|
|
32
|
+
*/
|
|
33
|
+
const TOOL_ARG_ALIASES = {
|
|
34
|
+
wordpress_read_page: { id: ['page_id', 'pageId', 'post_id', 'postId'] },
|
|
35
|
+
wordpress_read_post: { id: ['post_id', 'postId', 'page_id', 'pageId'] },
|
|
36
|
+
wordpress_create_page_duplicate: {
|
|
37
|
+
original_id: ['page_id', 'pageId', 'id', 'original_page_id', 'originalId'],
|
|
38
|
+
},
|
|
39
|
+
wordpress_create_post_duplicate: {
|
|
40
|
+
original_id: ['post_id', 'postId', 'id', 'original_post_id', 'originalId'],
|
|
41
|
+
},
|
|
42
|
+
wordpress_get_snapshot: { snapshot_uuid: ['snapshot_id', 'snapshotId', 'uuid', 'id'] },
|
|
43
|
+
wordpress_find_element: { post_id: ['page_id', 'pageId', 'id', 'postId'] },
|
|
44
|
+
wordpress_upload_media: {
|
|
45
|
+
file: ['filePath', 'file_path', 'path', 'url', 'file_url', 'fileUrl'],
|
|
46
|
+
filename: ['file_name', 'fileName', 'name'],
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Fill canonical argument keys from known synonyms, in place. No-op for tools
|
|
51
|
+
* without an alias entry and for args that already carry the canonical key.
|
|
52
|
+
*/
|
|
53
|
+
function normalizeToolArgs(canonicalName, args) {
|
|
54
|
+
if (!args || typeof args !== 'object')
|
|
55
|
+
return;
|
|
56
|
+
const aliases = TOOL_ARG_ALIASES[canonicalName];
|
|
57
|
+
if (!aliases)
|
|
58
|
+
return;
|
|
59
|
+
const record = args;
|
|
60
|
+
const isSet = (v) => v !== undefined && v !== null && v !== '';
|
|
61
|
+
for (const [canonical, synonyms] of Object.entries(aliases)) {
|
|
62
|
+
if (isSet(record[canonical]))
|
|
63
|
+
continue;
|
|
64
|
+
for (const syn of synonyms) {
|
|
65
|
+
if (isSet(record[syn])) {
|
|
66
|
+
record[canonical] = record[syn];
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
20
72
|
/**
|
|
21
73
|
* Read the server version from package.json at module load time so the
|
|
22
74
|
* MCP handshake, the `instructions` block, and the version-checker all
|
|
@@ -1163,6 +1215,12 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
1163
1215
|
// (wordpress_redeem_token) because normalizeToolName rewrites the
|
|
1164
1216
|
// respira_* alias to wordpress_* before dispatch.
|
|
1165
1217
|
const canonical = this.normalizeToolName(name).canonical;
|
|
1218
|
+
// Tolerate natural-but-wrong arg names from AI clients (pageId/page_id
|
|
1219
|
+
// vs id, filePath vs file). Fills canonical keys from synonyms in place
|
|
1220
|
+
// so a misnamed required param no longer yields /pages/undefined or an
|
|
1221
|
+
// empty "no response received" upload. No-op for tools without aliases;
|
|
1222
|
+
// an explicit canonical value is never overwritten.
|
|
1223
|
+
normalizeToolArgs(canonical, args);
|
|
1166
1224
|
if (canonical === 'wordpress_redeem_token') {
|
|
1167
1225
|
// redeemInstallToken returns a plain object. Wrap it in the standard
|
|
1168
1226
|
// MCP content envelope — the early-exit path bypasses the normal
|
|
@@ -4272,6 +4330,25 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
4272
4330
|
wordpress_write_theme_file: '7.0.42',
|
|
4273
4331
|
wordpress_append_theme_file: '7.0.42',
|
|
4274
4332
|
};
|
|
4333
|
+
/**
|
|
4334
|
+
* Capability negotiation Phase 2 (7.2.7): the feature flag each version-skewed
|
|
4335
|
+
* tool needs. From plugin 7.4.20 the compatibility endpoint declares these
|
|
4336
|
+
* flags from its LIVE registered REST routes, so this is an exact "does the
|
|
4337
|
+
* route exist on this install" signal — more precise than the version map
|
|
4338
|
+
* above and self-maintaining. The version map stays as the fallback for
|
|
4339
|
+
* plugins older than 7.4.20, which do not declare per-capability features yet.
|
|
4340
|
+
*/
|
|
4341
|
+
static TOOL_REQUIRED_FEATURE = {
|
|
4342
|
+
wordpress_run_pagespeed_audit: 'pagespeed',
|
|
4343
|
+
wordpress_analyze_pagespeed: 'pagespeed',
|
|
4344
|
+
wordpress_abilities_gap_report: 'abilities',
|
|
4345
|
+
wordpress_invoke_ability: 'abilities',
|
|
4346
|
+
wordpress_read_theme_file: 'theme_files',
|
|
4347
|
+
wordpress_write_theme_file: 'theme_files',
|
|
4348
|
+
wordpress_append_theme_file: 'theme_files',
|
|
4349
|
+
};
|
|
4350
|
+
/** First plugin version that declares per-capability features (Phase 2). */
|
|
4351
|
+
static FEATURE_DECL_MIN_PLUGIN_VERSION = '7.4.20';
|
|
4275
4352
|
/** True when version `a` is strictly older than `b` (both "x.y.z"). */
|
|
4276
4353
|
static versionLt(a, b) {
|
|
4277
4354
|
const pa = a.split('.').map((n) => parseInt(n, 10) || 0);
|
|
@@ -4312,6 +4389,12 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
4312
4389
|
/* non-fatal — fall through with whatever version we have (possibly null) */
|
|
4313
4390
|
}
|
|
4314
4391
|
const pluginVersion = this.currentSite.pluginVersion ?? null;
|
|
4392
|
+
// Phase 2 (7.2.7): plugin 7.4.20+ declares per-capability features from its
|
|
4393
|
+
// live REST routes; trust those exactly. Older plugins do not, so they fall
|
|
4394
|
+
// back to the version map in the per-tool gate below.
|
|
4395
|
+
const pluginFeatures = this.currentSite.pluginFeatures ?? [];
|
|
4396
|
+
const declaresFeatures = !!pluginVersion &&
|
|
4397
|
+
!RespiraWordPressServer.versionLt(pluginVersion, RespiraWordPressServer.FEATURE_DECL_MIN_PLUGIN_VERSION);
|
|
4315
4398
|
const detectedBuilder = (context?.page_builder?.name || '').toLowerCase();
|
|
4316
4399
|
const hasWooCommerce = Boolean(context?.woocommerce?.active || context?.addons?.woocommerce?.installed);
|
|
4317
4400
|
return tools.filter((tool) => {
|
|
@@ -4336,10 +4419,16 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
|
|
|
4336
4419
|
if (name.startsWith('woocommerce_')) {
|
|
4337
4420
|
return hasWooCommerce;
|
|
4338
4421
|
}
|
|
4339
|
-
// Capability negotiation: hide tools whose plugin route
|
|
4340
|
-
//
|
|
4341
|
-
//
|
|
4342
|
-
//
|
|
4422
|
+
// Capability negotiation: hide tools whose plugin route the connected site
|
|
4423
|
+
// does not expose (avoids rest_no_route 404s on version-skewed sites).
|
|
4424
|
+
// Prefer the plugin's declared per-capability features (7.4.20+, computed
|
|
4425
|
+
// from its live routes — exact), and fall back to the verified version map
|
|
4426
|
+
// for older plugins that do not declare them. Both are conservative: a tool
|
|
4427
|
+
// is hidden only on a positive signal that its route is absent.
|
|
4428
|
+
const reqFeature = RespiraWordPressServer.TOOL_REQUIRED_FEATURE[name];
|
|
4429
|
+
if (reqFeature && declaresFeatures) {
|
|
4430
|
+
return pluginFeatures.includes(reqFeature);
|
|
4431
|
+
}
|
|
4343
4432
|
const minPv = RespiraWordPressServer.TOOL_MIN_PLUGIN_VERSION[name];
|
|
4344
4433
|
if (minPv && pluginVersion && RespiraWordPressServer.versionLt(pluginVersion, minPv)) {
|
|
4345
4434
|
return false;
|