@respira/wordpress-mcp-server 8.3.10 → 8.3.12
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/CHANGELOG.md +6 -0
- package/dist/__tests__/empty-read-is-not-an-error.test.d.ts +2 -0
- package/dist/__tests__/empty-read-is-not-an-error.test.d.ts.map +1 -0
- package/dist/__tests__/empty-read-is-not-an-error.test.js +65 -0
- package/dist/__tests__/empty-read-is-not-an-error.test.js.map +1 -0
- package/dist/server.d.ts +32 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +2225 -206
- package/dist/server.js.map +1 -1
- package/package.json +4 -3
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,12 @@ All notable changes to Respira WordPress MCP Server will be documented in this f
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [8.3.12] - 2026-08-25
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **Every tool's read-only and destructive hints were delivered to nobody.** The catalog carried `readOnlyHint` as a top-level property of the tool object, sitting next to `name` and `description`. MCP puts those hints inside `annotations`, so every client looked for `tool.annotations.readOnlyHint`, found nothing, and fell back to the default: a write, potentially destructive. 133 hints had been written and shipped, and not one of them ever arrived. Nothing failed and nothing logged, which is why it lasted this long. All 319 tools now carry a complete block: `title`, `readOnlyHint`, `destructiveHint`, `idempotentHint` and `openWorldHint`. 136 are read-only, 156 write, 74 of those can destroy something, and 17 reach a system outside your site. Re-deriving the 165 hints that already existed contradicted none of them, so the values were right all along and only their address was wrong. A build check now fails on a tool with no annotations, on a hint that drifts back to the top level, and on the pairs that cannot both be true of one tool.
|
|
13
|
+
|
|
8
14
|
## [8.3.7] - 2026-08-19
|
|
9
15
|
|
|
10
16
|
### Fixed
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"empty-read-is-not-an-error.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/empty-read-is-not-an-error.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { test } from 'node:test';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import { isEmptyReadResult, readErrorCode, EMPTY_READ_TOOLS, EMPTY_READ_CODES } from '../server.js';
|
|
4
|
+
// A search that matched nothing is an answer, not a failure.
|
|
5
|
+
//
|
|
6
|
+
// Telemetry, 30 days to 2026-08-24: respira_element_not_found was the largest
|
|
7
|
+
// caller_error code at 4,626 calls, and 4,278 of them (92.5%) came from
|
|
8
|
+
// find_element itself. Across the read surface that was 5,695 calls over 318 of
|
|
9
|
+
// 716 sites reported to agents as errors. The agent-facing cost is that a failed
|
|
10
|
+
// search and a broken site look identical, so agents give up on pages they could
|
|
11
|
+
// have edited.
|
|
12
|
+
//
|
|
13
|
+
// These tests exist for the OTHER half: the narrowness. Turning an error into a
|
|
14
|
+
// success is the direction this codebase's worst bugs went, so the write path
|
|
15
|
+
// and the bad-site-id path must keep failing loudly.
|
|
16
|
+
test('a read tool reporting nothing found is not an error', () => {
|
|
17
|
+
for (const tool of ['find_element', 'get_option', 'read_page', 'get_media']) {
|
|
18
|
+
for (const prefix of ['', 'respira_', 'wordpress_']) {
|
|
19
|
+
assert.equal(isEmptyReadResult(prefix + tool, { name: 'respira_element_not_found' }), true, `${prefix}${tool} should be treated as an empty read`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
test('a WRITE reporting not-found stays an error', () => {
|
|
24
|
+
// The whole point of the narrowness. On a write, "not found" means the caller
|
|
25
|
+
// targeted something that does not exist, which it needs to hear about.
|
|
26
|
+
for (const tool of [
|
|
27
|
+
'update_element', 'remove_element', 'move_element', 'duplicate_element',
|
|
28
|
+
'batch_update', 'update_page', 'update_post', 'delete_page', 'apply_builder_patch',
|
|
29
|
+
]) {
|
|
30
|
+
for (const prefix of ['', 'respira_', 'wordpress_']) {
|
|
31
|
+
assert.equal(isEmptyReadResult(prefix + tool, { name: 'respira_element_not_found' }), false, `${prefix}${tool} is a write and must stay an error`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
test('a bad site id stays an error even on a read tool', () => {
|
|
36
|
+
// 410 calls over 25 sites in the same window. That is a misconfigured client,
|
|
37
|
+
// not an empty page, and it must not hide behind "nothing matched".
|
|
38
|
+
assert.equal(isEmptyReadResult('respira_find_element', { name: 'respira_site_id_not_found' }), false);
|
|
39
|
+
assert.equal(EMPTY_READ_CODES.has('respira_site_id_not_found'), false);
|
|
40
|
+
});
|
|
41
|
+
test('a read tool failing for any other reason stays an error', () => {
|
|
42
|
+
for (const code of [
|
|
43
|
+
'respira_no_builder', 'rest_no_route', 'http_500', 'respira_invalid_site_token',
|
|
44
|
+
'respira_rate_limit_exceeded', 'Error', '',
|
|
45
|
+
]) {
|
|
46
|
+
assert.equal(isEmptyReadResult('respira_find_element', { name: code }), false, `find_element + ${code || '(empty)'} must stay an error`);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
test('readErrorCode prefers the explicit code and falls back to the promoted name', () => {
|
|
50
|
+
assert.equal(readErrorCode({ code: 'respira_option_not_found' }), 'respira_option_not_found');
|
|
51
|
+
// wordpress-client promotes the WP_Error code onto error.name
|
|
52
|
+
assert.equal(readErrorCode({ name: 'respira_post_not_found' }), 'respira_post_not_found');
|
|
53
|
+
assert.equal(readErrorCode({ code: 'a', name: 'b' }), 'a');
|
|
54
|
+
assert.equal(readErrorCode({}), '');
|
|
55
|
+
assert.equal(readErrorCode(null), '');
|
|
56
|
+
});
|
|
57
|
+
test('every tool on the empty-read list reads rather than writes', () => {
|
|
58
|
+
// A name-shaped rule would quietly start swallowing errors the first time
|
|
59
|
+
// someone adds find_and_replace. This asserts the list stays a read list.
|
|
60
|
+
const writeVerbs = /(^|_)(update|create|delete|remove|move|duplicate|apply|inject|build|batch|upload|install|activate|save|import)(_|$)/;
|
|
61
|
+
for (const tool of EMPTY_READ_TOOLS) {
|
|
62
|
+
assert.ok(!writeVerbs.test(tool), `${tool} looks like a write and must not be on the empty-read list`);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
//# sourceMappingURL=empty-read-is-not-an-error.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"empty-read-is-not-an-error.test.js","sourceRoot":"","sources":["../../src/__tests__/empty-read-is-not-an-error.test.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
CHANGED
|
@@ -68,6 +68,38 @@ export declare function applyActiveSiteIdForConfig(state: RespiraMcpState, names
|
|
|
68
68
|
* agent would learn the wrong contract from a call that happened to work.
|
|
69
69
|
*/
|
|
70
70
|
export declare function requireAbilityName(args: Record<string, any> | undefined): string;
|
|
71
|
+
/**
|
|
72
|
+
* The read/search tools where "nothing matched" is a complete answer.
|
|
73
|
+
*
|
|
74
|
+
* An explicit list, not a regex on the tool name. `find_builder_targets` and
|
|
75
|
+
* `find_element` both start with "find" and so does nothing else that writes,
|
|
76
|
+
* but a name-shaped rule would quietly start swallowing errors the first time
|
|
77
|
+
* someone adds `find_and_replace`. The cost of this list is remembering to add
|
|
78
|
+
* to it; the cost of the regex is a silent write failure, and this codebase has
|
|
79
|
+
* paid that one before.
|
|
80
|
+
*
|
|
81
|
+
* Names are matched after stripping the `respira_` / `wordpress_` prefix, since
|
|
82
|
+
* both surfaces exist and the telemetry shows both in use.
|
|
83
|
+
*/
|
|
84
|
+
export declare const EMPTY_READ_TOOLS: Set<string>;
|
|
85
|
+
/**
|
|
86
|
+
* "Not found" codes that mean the search came back empty.
|
|
87
|
+
*
|
|
88
|
+
* respira_site_id_not_found is deliberately absent: that is the caller naming a
|
|
89
|
+
* site that does not exist, which is a caller mistake on any tool and must stay
|
|
90
|
+
* an error. It was 410 calls over 25 sites in the 30 days to 2026-08-24, and
|
|
91
|
+
* folding it in here would hide a misconfigured client behind a friendly
|
|
92
|
+
* "nothing matched".
|
|
93
|
+
*/
|
|
94
|
+
export declare const EMPTY_READ_CODES: Set<string>;
|
|
95
|
+
/** The WP_Error code, which wordpress-client promotes onto error.name. */
|
|
96
|
+
export declare function readErrorCode(error: any): string;
|
|
97
|
+
/**
|
|
98
|
+
* True when this is a read/search tool reporting that nothing matched.
|
|
99
|
+
* Both halves must hold: the wrong tool with the right code, or the right tool
|
|
100
|
+
* with any other code, stays an error.
|
|
101
|
+
*/
|
|
102
|
+
export declare function isEmptyReadResult(toolName: string, error: any): boolean;
|
|
71
103
|
export declare class RespiraWordPressServer {
|
|
72
104
|
private server;
|
|
73
105
|
private currentSite;
|
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;AAkBH,OAAO,KAAK,EAAE,mBAAmB,EAAe,MAAM,kBAAkB,CAAC;AAwCzE,MAAM,MAAM,eAAe,GAAG;IAC5B,0EAA0E;IAC1E,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,0EAA0E;IAC1E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,4EAA4E;IAC5E,qBAAqB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/C,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,eAAe,EACtB,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,IAAI,CAkBf;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,eAAe,EACtB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb,eAAe,CAUjB;AAqFD;;;;;;;;;;;;;;;;GAgBG;AACH;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,GAAG,MAAM,CAoBhF;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAkBH,OAAO,KAAK,EAAE,mBAAmB,EAAe,MAAM,kBAAkB,CAAC;AAwCzE,MAAM,MAAM,eAAe,GAAG;IAC5B,0EAA0E;IAC1E,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,0EAA0E;IAC1E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,4EAA4E;IAC5E,qBAAqB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/C,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,eAAe,EACtB,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,IAAI,CAkBf;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,eAAe,EACtB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,GACb,eAAe,CAUjB;AAqFD;;;;;;;;;;;;;;;;GAgBG;AACH;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,GAAG,MAAM,CAoBhF;AA0LD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,gBAAgB,aAkB3B,CAAC;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,aAW3B,CAAC;AAEH,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM,CAIhD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,OAAO,CAIvE;AAED,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;IACpC,iFAAiF;IACjF,OAAO,CAAC,iBAAiB,CAAK;IAC9B;;;OAGG;IACH,OAAO,CAAC,qBAAqB,CAMK;IAClC,iFAAiF;IACjF,OAAO,CAAC,mBAAmB,CAAgC;IAC3D;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA6B;IAE5D,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;IAgWvE,OAAO,CAAC,cAAc;IAItB;;;;;;;;;OASG;IACH,OAAO,CAAC,oBAAoB;IAkB5B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,aAAa;IAiCrB,gEAAgE;IAChE,OAAO,CAAC,aAAa;IAUrB;;;;;;OAMG;YACW,UAAU;IA2CxB;;;;;;;;;;;;;;OAcG;YACW,WAAW;IAiJzB;;;;;;;;;OASG;YACW,kBAAkB;IA4OhC;;;;;;;;OAQG;IACH,OAAO,CAAC,qBAAqB;IAgE7B;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;YACW,qBAAqB;IAkBnC;;;;;;;OAOG;IACH,OAAO,CAAC,yBAAyB;YAiCnB,kBAAkB;IAwGhC,yFAAyF;IACzF,OAAO,CAAC,gBAAgB;IASxB;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,CAAC,6BAA6B;IA6CrC;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,yBAAyB;IA+BjC,OAAO,CAAC,eAAe;IAmBvB,OAAO,CAAC,aAAa;YAoTP,kBAAkB;YAsClB,yBAAyB;IASvC;;;OAGG;IACH,OAAO,CAAC,oBAAoB;YAyBd,QAAQ;IAmsJtB;;;;;;OAMG;IACH;;;;;;;;;;;;;oDAagD;IAChD,OAAO,CAAC,mBAAmB,CAAoD;IAC/E,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAU;IAClD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,wBAAwB,CAAU;IAC1D,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,yBAAyB,CAAS;IAC1D;;mDAE+C;IAC/C,OAAO,CAAC,0BAA0B,CAAoC;IAEtE;;;;;;;;OAQG;YACW,0BAA0B;YAyC1B,oBAAoB;YA6CpB,2BAA2B;IAQzC;;;;OAIG;YACW,cAAc;IAQ5B,OAAO,CAAC,mBAAmB;IA4mE3B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,CAe3C;IAEF;;;;OAIG;IACH,OAAO,CAAC,0BAA0B;YAmCpB,cAAc;IA8H5B,oEAAoE;IACpE,OAAO,CAAC,iBAAiB;IAoBzB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,OAAO,CAAC,eAAe;YAuCT,gBAAgB;IA+9C9B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAsgBzB;;OAEG;IACH,OAAO,CAAC,sBAAsB;IA8VxB,GAAG;CA+CV"}
|