@respira/wordpress-mcp-server 8.1.6 → 8.2.1

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/CHANGELOG.md +19 -0
  2. package/README.md +7 -0
  3. package/TOOL_CATALOG.md +4 -1
  4. package/dist/__tests__/agent-signature-clientinfo.test.d.ts +2 -0
  5. package/dist/__tests__/agent-signature-clientinfo.test.d.ts.map +1 -0
  6. package/dist/__tests__/agent-signature-clientinfo.test.js +38 -0
  7. package/dist/__tests__/agent-signature-clientinfo.test.js.map +1 -0
  8. package/dist/__tests__/effective-config-observability.test.d.ts +2 -0
  9. package/dist/__tests__/effective-config-observability.test.d.ts.map +1 -0
  10. package/dist/__tests__/effective-config-observability.test.js +95 -0
  11. package/dist/__tests__/effective-config-observability.test.js.map +1 -0
  12. package/dist/__tests__/woo-card-tools-forward-fse-params.test.d.ts +2 -0
  13. package/dist/__tests__/woo-card-tools-forward-fse-params.test.d.ts.map +1 -0
  14. package/dist/__tests__/woo-card-tools-forward-fse-params.test.js +62 -0
  15. package/dist/__tests__/woo-card-tools-forward-fse-params.test.js.map +1 -0
  16. package/dist/agent-signature.d.ts +2 -1
  17. package/dist/agent-signature.d.ts.map +1 -1
  18. package/dist/agent-signature.js +64 -1
  19. package/dist/agent-signature.js.map +1 -1
  20. package/dist/config.d.ts +20 -0
  21. package/dist/config.d.ts.map +1 -1
  22. package/dist/config.js +54 -0
  23. package/dist/config.js.map +1 -1
  24. package/dist/server.d.ts.map +1 -1
  25. package/dist/server.js +144 -0
  26. package/dist/server.js.map +1 -1
  27. package/dist/wordpress-client.d.ts.map +1 -1
  28. package/dist/wordpress-client.js +14 -0
  29. package/dist/wordpress-client.js.map +1 -1
  30. package/package.json +1 -1
  31. package/tool-capabilities.json +40 -4
package/CHANGELOG.md CHANGED
@@ -5,6 +5,25 @@ 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.2.1] - 2026-08-04
9
+
10
+ ### Added
11
+
12
+ - **`diagnose_connection` reports the effective client configuration.** It already reported process facts (version, pid, binary path, sibling processes); it did not report the configuration those facts were operating on. It now names the winning config source, where it is, how many sites resolved and which, and warns on the two misleading states: a `RESPIRA_CONFIG_B64` override meaning the file on disk is not being read, and one site resolving when the account has more. Three customers in two weeks lost time to three different mechanisms — a lapsed licence leaving keys dead, a redeem writing a config nothing read, and an old npx entry winning over a newly installed Desktop bundle — with this one missing instrument in common. Every one of them had to read config files to find out what was in use.
13
+ - **`redeem_token` verifies its own write.** It writes the config, reads it back, and reports what landed and whether the next start will read it. Previously it wrote a file and reported success, which is true and useless when an environment variable outranks that file.
14
+ - **`edit_target` and `verification_marker` on the four WooCommerce card tools.** Both were already forwarded to the FSE layer by the add-on; the schemas never declared them, so they could not be supplied.
15
+
16
+ ## [8.2.0] - 2026-08-03
17
+
18
+ ### Added
19
+
20
+ - **Resonance memory tools.** `wordpress_remember`, `wordpress_forget`, and `wordpress_list_memory` maintain a persistent per-site memory on the WordPress site itself (plugin 8.3+). The tool descriptions teach the loop: save durable preferences and corrections, ask before storing anything the user did not state, and never work around a rule refusal, because rules of type `rule` are enforced server side by the plugin.
21
+ - **Memory-aware session priming.** The handshake instructions gain a golden rule for honoring and growing Site Memory, and `get_site_context` carries the `site_memory` block through the compact `detail: basic` projection, so every session starts warm regardless of detail level.
22
+
23
+ ### Fixed
24
+
25
+ - **claude.ai traffic is no longer mislabeled as Claude Code.** Client-reported `clientInfo` now takes precedence over user-agent heuristics when resolving the agent label, with tests pinning the claude.ai versus claude-code split. Connection-mix telemetry depends on this being honest.
26
+
8
27
  ## [8.1.6] - 2026-08-02
9
28
 
10
29
  ### Fixed
package/README.md CHANGED
@@ -35,6 +35,13 @@ Other WordPress MCP servers wrap the REST API. They can create posts and pages,
35
35
 
36
36
  Respira includes a WordPress plugin that gives AI **native access** to 17 page builders, plus element-level precision, full page creation from structure, HTML-to-builder conversion, storefront design intelligence, stock image search, and bulk operations across hundreds of pages.
37
37
 
38
+ ### New in 8.2: Resonance, a persistent memory for every site
39
+
40
+ - **Your AI forgets your site every session. Resonance remembers.** `wordpress_remember`, `wordpress_forget`, and `wordpress_list_memory` maintain a capped, per-site store of conventions, preferences, and lessons that rides into the site context of every future session, from any connected client.
41
+ - **Rules are enforced, not suggested.** A memory of type `rule` can protect content (post ids or slugs); the WordPress plugin refuses agent writes to protected content at the write path, server side. Agents can add protection in conversation; only the site owner can remove it, from the Respira dashboard.
42
+ - **Compatible with WordPress core's Knowledge direction.** On sites running the Gutenberg Knowledge experiment, published guideline scopes join the same memory block.
43
+ - Included on Builder and Studio plans with plugin 8.3+, at no extra cost.
44
+
38
45
  ### New in 8.1: MCP 2026-07-28, without breaking existing clients
39
46
 
40
47
  - **Modern protocol negotiation.** Compatible clients can use `server/discover` and negotiate MCP `2026-07-28`, including stateless per-request metadata and typed result contracts.
package/TOOL_CATALOG.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  <!-- Generated by scripts/check-tool-registry-parity.mjs. Do not edit by hand. -->
4
4
 
5
- Generated catalog: **171 core tools**, **105 WooCommerce tools**, **276 total**.
5
+ Generated catalog: **174 core tools**, **105 WooCommerce tools**, **279 total**.
6
6
 
7
7
  The runtime applies site context and per-site governance, so an individual connection may expose a smaller relevant subset.
8
8
 
@@ -74,6 +74,7 @@ The runtime applies site context and per-site governance, so an individual conne
74
74
  - `wordpress_extract_builder_content` — read; native + hosted
75
75
  - `wordpress_find_builder_targets` — read; native + hosted
76
76
  - `wordpress_find_element` — read; native + hosted
77
+ - `wordpress_forget` — read; native + hosted
77
78
  - `wordpress_get_accessibility_scan` — read; hosted/stdio
78
79
  - `wordpress_get_active_site` — read; hosted/stdio
79
80
  - `wordpress_get_activity` — read; native + hosted
@@ -113,6 +114,7 @@ The runtime applies site context and per-site governance, so an individual conne
113
114
  - `wordpress_list_custom_taxonomies` — read; hosted/stdio
114
115
  - `wordpress_list_design_tokens` — read; native + hosted
115
116
  - `wordpress_list_media` — read; native + hosted
117
+ - `wordpress_list_memory` — read; native + hosted
116
118
  - `wordpress_list_menu_items` — read; native + hosted
117
119
  - `wordpress_list_menu_locations` — read; native + hosted
118
120
  - `wordpress_list_menus` — read; native + hosted
@@ -137,6 +139,7 @@ The runtime applies site context and per-site governance, so an individual conne
137
139
  - `wordpress_read_post` — read; native + hosted
138
140
  - `wordpress_read_theme_file` — read; hosted/stdio
139
141
  - `wordpress_redeem_token` — write; hosted/stdio
142
+ - `wordpress_remember` — read; native + hosted
140
143
  - `wordpress_remove_element` — write; native + hosted
141
144
  - `wordpress_reorder_elements` — write; native + hosted
142
145
  - `wordpress_report_issue` — read; hosted/stdio
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=agent-signature-clientinfo.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-signature-clientinfo.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/agent-signature-clientinfo.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Phase A attribution: the MCP initialize handshake's clientInfo outranks
3
+ * process heuristics but never an explicit env pin, and raw client names
4
+ * normalize to canonical slugs (a bare "Claude ..." over local stdio is the
5
+ * Desktop app; only claude.ai/web connectors never spawn this process).
6
+ */
7
+ import { test } from 'node:test';
8
+ import assert from 'node:assert';
9
+ import { detectRespiraAgentSignature, setMcpClientInfo } from '../agent-signature.js';
10
+ test('clientInfo outranks heuristics and normalizes names', () => {
11
+ delete process.env.RESPIRA_AGENT_CLIENT;
12
+ delete process.env.MCP_AGENT_CLIENT;
13
+ delete process.env.AI_AGENT_CLIENT;
14
+ setMcpClientInfo('Claude Desktop', '1.2.3');
15
+ const sig = detectRespiraAgentSignature();
16
+ assert.strictEqual(sig.client, 'claude-desktop');
17
+ assert.strictEqual(sig.source, 'client-info');
18
+ assert.strictEqual(sig.version, '1.2.3');
19
+ });
20
+ test('claude-code self-identification stays claude-code', () => {
21
+ setMcpClientInfo('claude-code', '2.0.0');
22
+ assert.strictEqual(detectRespiraAgentSignature().client, 'claude-code');
23
+ });
24
+ test('unknown but self-declared clients keep their sanitized name', () => {
25
+ setMcpClientInfo('SomeNew Agent!', null);
26
+ const sig = detectRespiraAgentSignature();
27
+ assert.strictEqual(sig.source, 'client-info');
28
+ assert.strictEqual(sig.client, 'somenewagent');
29
+ });
30
+ test('an explicit env pin still wins over clientInfo', () => {
31
+ setMcpClientInfo('Cursor', '9.9');
32
+ process.env.RESPIRA_AGENT_CLIENT = 'my-custom-rig';
33
+ const sig = detectRespiraAgentSignature();
34
+ assert.strictEqual(sig.client, 'my-custom-rig');
35
+ assert.strictEqual(sig.source, 'env');
36
+ delete process.env.RESPIRA_AGENT_CLIENT;
37
+ });
38
+ //# sourceMappingURL=agent-signature-clientinfo.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-signature-clientinfo.test.js","sourceRoot":"","sources":["../../src/__tests__/agent-signature-clientinfo.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,2BAA2B,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEtF,IAAI,CAAC,qDAAqD,EAAE,GAAG,EAAE;IAC/D,OAAO,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;IACxC,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IACpC,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IAEnC,gBAAgB,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;IAC5C,MAAM,GAAG,GAAG,2BAA2B,EAAE,CAAC;IAC1C,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IACjD,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC9C,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAC3C,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,mDAAmD,EAAE,GAAG,EAAE;IAC7D,gBAAgB,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IACzC,MAAM,CAAC,WAAW,CAAC,2BAA2B,EAAE,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;AAC1E,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,6DAA6D,EAAE,GAAG,EAAE;IACvE,gBAAgB,CAAC,gBAAgB,EAAE,IAAW,CAAC,CAAC;IAChD,MAAM,GAAG,GAAG,2BAA2B,EAAE,CAAC;IAC1C,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAC9C,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;AACjD,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,gDAAgD,EAAE,GAAG,EAAE;IAC1D,gBAAgB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAClC,OAAO,CAAC,GAAG,CAAC,oBAAoB,GAAG,eAAe,CAAC;IACnD,MAAM,GAAG,GAAG,2BAA2B,EAAE,CAAC;IAC1C,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IAChD,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACtC,OAAO,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;AAC1C,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=effective-config-observability.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effective-config-observability.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/effective-config-observability.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,95 @@
1
+ import { describe, it, afterEach } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { describeEffectiveConfig } from '../config.js';
4
+ /**
5
+ * Three customers in two weeks lost time to the same missing instrument.
6
+ *
7
+ * M.O. a lapsed licence left his API keys dead. Found it by dumping his
8
+ * own database.
9
+ * M.S. redeem returns nothing and never adds a second site.
10
+ * Desmond installed the Desktop bundle while an older npx entry kept
11
+ * winning, and stayed on one site for three weeks while the
12
+ * dashboard said all five were included.
13
+ *
14
+ * Three different mechanisms. What they share is that the client's EFFECTIVE
15
+ * configuration is invisible, and can differ from what a tool reported writing.
16
+ * Every one of them had to read config files, or have telemetry read for them.
17
+ *
18
+ * describeEffectiveConfig is that instrument. These tests pin the two things it
19
+ * must never get wrong: naming the source that actually won, and never leaking
20
+ * a token into output a customer will paste into a support thread.
21
+ */
22
+ const ORIGINAL = { ...process.env };
23
+ afterEach(() => {
24
+ process.env = { ...ORIGINAL };
25
+ });
26
+ describe('describeEffectiveConfig', () => {
27
+ it('names RESPIRA_CONFIG_B64 as the winner when it is set', () => {
28
+ process.env.RESPIRA_CONFIG_B64 = 'eyJzaXRlcyI6W119';
29
+ process.env.RESPIRA_CONFIG_FILE = '/somewhere/else/config.json';
30
+ const d = describeEffectiveConfig([{ id: 'a', url: 'https://a.com' }]);
31
+ assert.equal(d.config_source, 'RESPIRA_CONFIG_B64');
32
+ assert.equal(d.config_b64_active, true);
33
+ });
34
+ it('warns that a redeem writing the file will not be read under B64', () => {
35
+ process.env.RESPIRA_CONFIG_B64 = 'eyJzaXRlcyI6W119';
36
+ const d = describeEffectiveConfig([{ id: 'a', url: 'https://a.com' }]);
37
+ const notes = d.notes.join(' ');
38
+ assert.match(notes, /NOT reading the config file/);
39
+ assert.match(notes, /will not change what this process sees/);
40
+ });
41
+ it('falls back to the explicit file when no B64 is set', () => {
42
+ delete process.env.RESPIRA_CONFIG_B64;
43
+ process.env.RESPIRA_CONFIG_FILE = '/custom/path/config.json';
44
+ const d = describeEffectiveConfig([]);
45
+ assert.equal(d.config_source, 'RESPIRA_CONFIG_FILE');
46
+ assert.equal(d.config_b64_active, false);
47
+ assert.match(String(d.config_location), /\/custom\/path\/config\.json/);
48
+ });
49
+ it('falls back to the default path when neither is set', () => {
50
+ delete process.env.RESPIRA_CONFIG_B64;
51
+ delete process.env.RESPIRA_CONFIG_FILE;
52
+ const d = describeEffectiveConfig([]);
53
+ assert.equal(d.config_source, 'default file');
54
+ assert.match(String(d.config_location), /\.respira\/config\.json/);
55
+ });
56
+ it("explains Desmond's case: one site resolved while the account has more", () => {
57
+ delete process.env.RESPIRA_CONFIG_B64;
58
+ const d = describeEffectiveConfig([{ id: 'staging', url: 'https://staging.sactrust.org' }]);
59
+ assert.equal(d.resolved_site_count, 1);
60
+ const notes = d.notes.join(' ');
61
+ assert.match(notes, /second, older MCP entry/);
62
+ });
63
+ it('does not nag when several sites resolved', () => {
64
+ delete process.env.RESPIRA_CONFIG_B64;
65
+ const d = describeEffectiveConfig([
66
+ { id: 'a', url: 'https://a.com' },
67
+ { id: 'b', url: 'https://b.com' },
68
+ ]);
69
+ assert.equal(d.resolved_site_count, 2);
70
+ assert.doesNotMatch(d.notes.join(' '), /older MCP entry/);
71
+ });
72
+ it('flags bootstrap mode when nothing resolved', () => {
73
+ const d = describeEffectiveConfig([]);
74
+ assert.match(d.notes.join(' '), /bootstrap mode/);
75
+ });
76
+ it('lists the sites it resolved, so the count is checkable', () => {
77
+ const d = describeEffectiveConfig([
78
+ { id: 'a', url: 'https://a.com' },
79
+ { id: 'b', url: 'https://b.com' },
80
+ ]);
81
+ assert.deepEqual(d.resolved_sites, [
82
+ { id: 'a', url: 'https://a.com' },
83
+ { id: 'b', url: 'https://b.com' },
84
+ ]);
85
+ });
86
+ it('never emits a token — this output gets pasted into support threads', () => {
87
+ process.env.RESPIRA_CONFIG_B64 = Buffer.from(JSON.stringify({ sites: [{ id: 'a', url: 'https://a.com', apiKey: 'respira_site_SECRET' }] })).toString('base64');
88
+ const serialised = JSON.stringify(describeEffectiveConfig([{ id: 'a', url: 'https://a.com' }]));
89
+ assert.doesNotMatch(serialised, /SECRET/);
90
+ assert.doesNotMatch(serialised, /respira_site_/);
91
+ // The base64 blob itself would decode to the key, so it must not appear either.
92
+ assert.doesNotMatch(serialised, /eyJ/);
93
+ });
94
+ });
95
+ //# sourceMappingURL=effective-config-observability.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effective-config-observability.test.js","sourceRoot":"","sources":["../../src/__tests__/effective-config-observability.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=woo-card-tools-forward-fse-params.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"woo-card-tools-forward-fse-params.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/woo-card-tools-forward-fse-params.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,62 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { readFileSync } from 'node:fs';
4
+ /**
5
+ * The four WooCommerce card tools call the same FSE layer as
6
+ * update_site_template. The add-on has always forwarded edit_target and
7
+ * verification_marker to it (class-storefront-tools.php update_fse_template),
8
+ * so the plumbing existed the whole time — but the MCP tool schemas never
9
+ * declared either parameter, and a client only sends declared properties.
10
+ *
11
+ * The consequence D.L. measured: a Woo card write always produced
12
+ * state=pending_approval with mutation_performed=false, while core
13
+ * update-site-template against the same target and path with edit_target=live
14
+ * wrote directly. So storefront card edits always required wp-admin approval no
15
+ * matter how the site was configured, and always fell back to whole-page hash
16
+ * comparison whether or not the caller could supply a better marker.
17
+ *
18
+ * On verification_marker he explicitly accepted the earlier decision NOT to
19
+ * auto-generate markers — a marker derived from a generic value could match
20
+ * unrelated content and pass falsely. This is passthrough only.
21
+ */
22
+ // Read the SOURCE, not the compiled file: this asserts on the tool schema as
23
+ // authored. Tests run from the package root, so resolve from cwd rather than
24
+ // import.meta.url, which points into dist/ where no .ts exists.
25
+ const SRC = readFileSync(`${process.cwd()}/src/server.ts`, 'utf8');
26
+ const CARD_TOOLS = [
27
+ 'woocommerce_update_storefront_card_field',
28
+ 'woocommerce_update_product_card_layout',
29
+ 'woocommerce_add_sale_badge',
30
+ 'woocommerce_add_low_stock_badge',
31
+ ];
32
+ /** Slice out one tool's schema block so assertions cannot drift to a neighbour. */
33
+ function schemaOf(tool) {
34
+ const start = SRC.indexOf(`name: '${tool}',`);
35
+ assert.notEqual(start, -1, `tool ${tool} not found`);
36
+ const end = SRC.indexOf('required:', start);
37
+ return SRC.slice(start, end === -1 ? start + 4000 : end);
38
+ }
39
+ describe('Woo card tools expose the FSE parameters they already forward', () => {
40
+ for (const tool of CARD_TOOLS) {
41
+ it(`${tool} declares edit_target`, () => {
42
+ assert.match(schemaOf(tool), /edit_target:/);
43
+ });
44
+ it(`${tool} declares verification_marker`, () => {
45
+ assert.match(schemaOf(tool), /verification_marker:/);
46
+ });
47
+ it(`${tool} constrains edit_target to live or duplicate`, () => {
48
+ assert.match(schemaOf(tool), /enum: \['live', 'duplicate'\]/);
49
+ });
50
+ }
51
+ it('says direct edit is refused rather than silently downgraded without the site option', () => {
52
+ const s = schemaOf('woocommerce_update_storefront_card_field');
53
+ assert.match(s, /respira_allow_direct_edit/);
54
+ assert.match(s, /refused rather than silently downgraded/);
55
+ });
56
+ it('records that the marker is never auto-generated, and why', () => {
57
+ const s = schemaOf('woocommerce_add_sale_badge');
58
+ assert.match(s, /Never auto-generated/);
59
+ assert.match(s, /match unrelated content/);
60
+ });
61
+ });
62
+ //# sourceMappingURL=woo-card-tools-forward-fse-params.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"woo-card-tools-forward-fse-params.test.js","sourceRoot":"","sources":["../../src/__tests__/woo-card-tools-forward-fse-params.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC;;;;;;;;;;;;;;;;;GAiBG;AAEH,6EAA6E;AAC7E,6EAA6E;AAC7E,gEAAgE;AAChE,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,OAAO,CAAC,GAAG,EAAE,gBAAgB,EAAE,MAAM,CAAC,CAAC;AAEnE,MAAM,UAAU,GAAG;IACjB,0CAA0C;IAC1C,wCAAwC;IACxC,4BAA4B;IAC5B,iCAAiC;CAClC,CAAC;AAEF,mFAAmF;AACnF,SAAS,QAAQ,CAAC,IAAY;IAC5B,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC;IAC9C,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,QAAQ,IAAI,YAAY,CAAC,CAAC;IACrD,MAAM,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;IAC5C,OAAO,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAC3D,CAAC;AAED,QAAQ,CAAC,+DAA+D,EAAE,GAAG,EAAE;IAC7E,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,EAAE,CAAC,GAAG,IAAI,uBAAuB,EAAE,GAAG,EAAE;YACtC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,cAAc,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,GAAG,IAAI,+BAA+B,EAAE,GAAG,EAAE;YAC9C,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,sBAAsB,CAAC,CAAC;QACvD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,GAAG,IAAI,8CAA8C,EAAE,GAAG,EAAE;YAC7D,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,+BAA+B,CAAC,CAAC;QAChE,CAAC,CAAC,CAAC;IACL,CAAC;IAED,EAAE,CAAC,qFAAqF,EAAE,GAAG,EAAE;QAC7F,MAAM,CAAC,GAAG,QAAQ,CAAC,0CAA0C,CAAC,CAAC;QAC/D,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,2BAA2B,CAAC,CAAC;QAC7C,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,yCAAyC,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,MAAM,CAAC,GAAG,QAAQ,CAAC,4BAA4B,CAAC,CAAC;QACjD,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,sBAAsB,CAAC,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,yBAAyB,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -8,8 +8,9 @@ export interface RespiraAgentSignature {
8
8
  client: string;
9
9
  version: string | null;
10
10
  transport: string;
11
- source: 'env' | 'heuristic' | 'default';
11
+ source: 'env' | 'client-info' | 'heuristic' | 'default';
12
12
  }
13
+ export declare function setMcpClientInfo(name: unknown, version?: unknown): void;
13
14
  export declare function detectRespiraAgentSignature(): RespiraAgentSignature;
14
15
  export declare function getRespiraAgentHeaders(): Record<string, string>;
15
16
  //# sourceMappingURL=agent-signature.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"agent-signature.d.ts","sourceRoot":"","sources":["../src/agent-signature.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,KAAK,GAAG,WAAW,GAAG,SAAS,CAAC;CACzC;AAwGD,wBAAgB,2BAA2B,IAAI,qBAAqB,CAgBnE;AAED,wBAAgB,sBAAsB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAa/D"}
1
+ {"version":3,"file":"agent-signature.d.ts","sourceRoot":"","sources":["../src/agent-signature.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,KAAK,GAAG,aAAa,GAAG,WAAW,GAAG,SAAS,CAAC;CACzD;AAkCD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAQvE;AAwGD,wBAAgB,2BAA2B,IAAI,qBAAqB,CA4BnE;AAED,wBAAgB,sBAAsB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAa/D"}
@@ -6,6 +6,58 @@
6
6
  */
7
7
  import { execSync } from 'node:child_process';
8
8
  const MAX_HEADER_VALUE = 64;
9
+ /**
10
+ * The MCP initialize handshake carries the client's SELF-DECLARED identity
11
+ * (clientInfo.name/version). It is the highest-trust signal short of an
12
+ * explicit env override: the ps-parent heuristic below misfiles ambiguous
13
+ * cases (a bare `claude` parent buckets as claude-code, undercounting
14
+ * Claude Desktop), while clientInfo is what the app says it is. The server
15
+ * stores it here after initialization; every subsequent header/telemetry
16
+ * read picks it up. Phase A of the connection-mix attribution work.
17
+ */
18
+ let mcpClientInfo = null;
19
+ /** Normalize a raw clientInfo.name to Respira's canonical client slugs. */
20
+ function normalizeClientInfoName(raw) {
21
+ const n = raw.trim().toLowerCase();
22
+ if (!n)
23
+ return null;
24
+ if (n.includes('cowork'))
25
+ return 'cowork';
26
+ if (n.includes('claude-code') || n.includes('claude code'))
27
+ return 'claude-code';
28
+ // Any other Claude identity arriving over local stdio is the Desktop app
29
+ // (claude.ai/web connectors never spawn this process).
30
+ if (n.includes('claude'))
31
+ return 'claude-desktop';
32
+ if (n.includes('cursor'))
33
+ return 'cursor';
34
+ if (n.includes('windsurf') || n.includes('codeium'))
35
+ return 'windsurf';
36
+ if (n.includes('codex'))
37
+ return 'codex';
38
+ if (n.includes('chatgpt') || n.includes('openai'))
39
+ return 'chatgpt';
40
+ if (n.includes('copilot'))
41
+ return 'copilot';
42
+ if (n.includes('gemini') || n.includes('antigravity'))
43
+ return n.includes('antigravity') ? 'antigravity' : 'gemini';
44
+ if (n.includes('opencode'))
45
+ return 'opencode';
46
+ // Unknown but self-declared: keep the sanitized raw name rather than
47
+ // guessing. It surfaces new clients in telemetry instead of hiding them.
48
+ return sanitizeHeaderToken(n);
49
+ }
50
+ export function setMcpClientInfo(name, version) {
51
+ if (typeof name !== 'string' || !name.trim())
52
+ return;
53
+ const client = normalizeClientInfoName(name);
54
+ if (!client)
55
+ return;
56
+ mcpClientInfo = {
57
+ client,
58
+ version: sanitizeHeaderToken(typeof version === 'string' ? version : null),
59
+ };
60
+ }
9
61
  function sanitizeHeaderToken(value, fallback = null) {
10
62
  if (typeof value !== 'string') {
11
63
  return fallback;
@@ -112,8 +164,19 @@ export function detectRespiraAgentSignature() {
112
164
  const explicitClient = sanitizeHeaderToken(process.env.RESPIRA_AGENT_CLIENT) ||
113
165
  sanitizeHeaderToken(process.env.MCP_AGENT_CLIENT) ||
114
166
  sanitizeHeaderToken(process.env.AI_AGENT_CLIENT);
115
- const client = explicitClient || detectClientFromHeuristics();
116
167
  const transport = sanitizeHeaderToken(process.env.RESPIRA_AGENT_TRANSPORT, 'desktop-mcp') || 'desktop-mcp';
168
+ // Precedence: explicit env pin > the client's own initialize handshake >
169
+ // process heuristics. The env override stays on top deliberately: it is
170
+ // how a user corrects us when everything else is wrong.
171
+ if (!explicitClient && mcpClientInfo) {
172
+ return {
173
+ client: mcpClientInfo.client,
174
+ version: mcpClientInfo.version || detectVersion(mcpClientInfo.client),
175
+ transport,
176
+ source: 'client-info',
177
+ };
178
+ }
179
+ const client = explicitClient || detectClientFromHeuristics();
117
180
  return {
118
181
  client,
119
182
  version: detectVersion(client),
@@ -1 +1 @@
1
- {"version":3,"file":"agent-signature.js","sourceRoot":"","sources":["../src/agent-signature.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"agent-signature.js","sourceRoot":"","sources":["../src/agent-signature.ts"],"names":[],"mappings":"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"}
package/dist/config.d.ts CHANGED
@@ -125,4 +125,24 @@ export declare function setDefaultSite(siteId: string): void;
125
125
  * Test connection to a WordPress site
126
126
  */
127
127
  export declare function testConnection(siteId: string): Promise<void>;
128
+ /**
129
+ * Describe the configuration this process is ACTUALLY running on.
130
+ *
131
+ * Resolution order is RESPIRA_CONFIG_B64, then RESPIRA_CONFIG_FILE, then
132
+ * ~/.respira/config.json. Only the winner matters, and until now nothing
133
+ * reported which one won. That gap is the common factor behind three separate
134
+ * customer incidents whose mechanisms were all different: a redeem that wrote a
135
+ * file an env var was already overriding, a Desktop bundle installed alongside
136
+ * an older npx entry that kept winning, and a licence lapse that left the keys
137
+ * in the winning config dead.
138
+ *
139
+ * Deliberately reports the config PATH but never the tokens. A customer pastes
140
+ * this output into a support thread.
141
+ *
142
+ * @param sites Sites the running server actually resolved.
143
+ */
144
+ export declare function describeEffectiveConfig(sites: Array<{
145
+ id?: string;
146
+ url?: string;
147
+ }>): Record<string, unknown>;
128
148
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAE3E,eAAO,MAAM,UAAU,QAA8B,CAAC;AACtD,eAAO,MAAM,WAAW,QAAkC,CAAC;AAE3D;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAmBpD;AAED,+EAA+E;AAC/E,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAErD;AAaD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,mBAAmB,EAAE,EACpC,QAAQ,EAAE,mBAAmB,EAAE,GAC9B,mBAAmB,EAAE,CAkBvB;AAED,wBAAgB,gBAAgB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAG9E;AAwED;;;;;;;;;;;;GAYG;AACH;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CA2BvE;AAgDD,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,aAAa,CA0H/G;AA6BD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAO5D;AAmGD;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,IAAI,aAAa,CA0E1C;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAOtD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAO1E;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,mBAAmB,GAAG,IAAI,CAavD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAe/C;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAYnD;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBlE"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAE3E,eAAO,MAAM,UAAU,QAA8B,CAAC;AACtD,eAAO,MAAM,WAAW,QAAkC,CAAC;AAE3D;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAmBpD;AAED,+EAA+E;AAC/E,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAErD;AAaD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAChC,aAAa,EAAE,mBAAmB,EAAE,EACpC,QAAQ,EAAE,mBAAmB,EAAE,GAC9B,mBAAmB,EAAE,CAkBvB;AAED,wBAAgB,gBAAgB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAG9E;AAwED;;;;;;;;;;;;GAYG;AACH;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CA2BvE;AAgDD,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,aAAa,CA0H/G;AA6BD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAO5D;AAmGD;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,IAAI,aAAa,CA0E1C;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAOtD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAO1E;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,IAAI,EAAE,mBAAmB,GAAG,IAAI,CAavD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAe/C;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAYnD;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAmBlE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,KAAK,CAAC;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA2C5G"}
package/dist/config.js CHANGED
@@ -657,4 +657,58 @@ export async function testConnection(siteId) {
657
657
  throw new Error(`Connection test failed: ${error.message}`);
658
658
  }
659
659
  }
660
+ /**
661
+ * Describe the configuration this process is ACTUALLY running on.
662
+ *
663
+ * Resolution order is RESPIRA_CONFIG_B64, then RESPIRA_CONFIG_FILE, then
664
+ * ~/.respira/config.json. Only the winner matters, and until now nothing
665
+ * reported which one won. That gap is the common factor behind three separate
666
+ * customer incidents whose mechanisms were all different: a redeem that wrote a
667
+ * file an env var was already overriding, a Desktop bundle installed alongside
668
+ * an older npx entry that kept winning, and a licence lapse that left the keys
669
+ * in the winning config dead.
670
+ *
671
+ * Deliberately reports the config PATH but never the tokens. A customer pastes
672
+ * this output into a support thread.
673
+ *
674
+ * @param sites Sites the running server actually resolved.
675
+ */
676
+ export function describeEffectiveConfig(sites) {
677
+ const b64 = process.env.RESPIRA_CONFIG_B64?.trim();
678
+ const explicitFile = process.env.RESPIRA_CONFIG_FILE?.trim();
679
+ let source;
680
+ let sourceDetail;
681
+ if (b64) {
682
+ source = 'RESPIRA_CONFIG_B64';
683
+ sourceDetail = 'environment variable (takes precedence over any file on disk)';
684
+ }
685
+ else if (explicitFile) {
686
+ source = 'RESPIRA_CONFIG_FILE';
687
+ sourceDetail = expandHomePath(explicitFile);
688
+ }
689
+ else {
690
+ source = 'default file';
691
+ sourceDetail = '~/.respira/config.json';
692
+ }
693
+ const resolved = sites.map((s) => ({ id: s.id ?? null, url: s.url ?? null }));
694
+ const notes = [];
695
+ if (b64) {
696
+ notes.push('RESPIRA_CONFIG_B64 is set, so this server is NOT reading the config file. ' +
697
+ 'A redeem that writes the file will not change what this process sees until the variable is updated and the client restarted.');
698
+ }
699
+ if (resolved.length === 1) {
700
+ notes.push('Only one site resolved. If the dashboard says your account has more, the likely cause is a second, older MCP entry in your client winning over a newer one, or a config written somewhere this process is not reading.');
701
+ }
702
+ if (resolved.length === 0) {
703
+ notes.push('No sites resolved. The server is in bootstrap mode; only redeem_token will work.');
704
+ }
705
+ return {
706
+ config_source: source,
707
+ config_location: sourceDetail,
708
+ config_b64_active: Boolean(b64),
709
+ resolved_site_count: resolved.length,
710
+ resolved_sites: resolved,
711
+ notes,
712
+ };
713
+ }
660
714
  //# sourceMappingURL=config.js.map