@respira/wordpress-mcp-server 8.1.5 → 8.2.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/dist/server.js CHANGED
@@ -4,6 +4,7 @@
4
4
  * Provides tools for AI coding assistants to interact with WordPress sites
5
5
  */
6
6
  import { Server } from '@modelcontextprotocol/server';
7
+ import { setMcpClientInfo } from './agent-signature.js';
7
8
  import { serveStdio } from '@modelcontextprotocol/server/stdio';
8
9
  import { execSync } from 'child_process';
9
10
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
@@ -347,6 +348,7 @@ Follow these on every site. They are what separates a great result from a frustr
347
348
  5. Load schemas before writing. Use respira_get_builder_inline_schemas (or the per-builder schema tools) so attribute shapes are exact, not improvised.
348
349
  6. Dropped styling is not a retry. If a write returns dropped_styling_hint or a STYLING DROPPED message, the builder did not recognize that setting. Do NOT re-send the same write. Pick a supported attribute or move that bit into a code block, then write again. (This is the single biggest source of wasted retries.)
349
350
  7. Design-system first. When the builder exposes a design system, read it before building and reuse existing tokens instead of inventing styles: respira_bricks_design_system (Bricks global classes/colors/typography), respira_elementor_design_system (Elementor global colors/typography), and Divi 5 presets/color tokens. This keeps results on-brand and maintainable.
351
+ 8. Honor and grow Site Memory. get_site_context / get_builder_info include a site_memory block: rules are hard constraints the plugin enforces (protected content refuses writes — never work around a refusal, tell the user), notes are the site's accumulated conventions. When the user states a durable preference or corrects a mistake worth not repeating, offer to save it with respira_remember so the next session starts warm.
350
352
 
351
353
  ## Tool naming
352
354
 
@@ -574,6 +576,18 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
574
576
 
575
577
  21 tools for product management, categories, tags, orders, stock, and sales reports. All prefixed woocommerce_*.`,
576
578
  });
579
+ // Capture the client's self-declared identity from the MCP initialize
580
+ // handshake (highest-trust attribution signal short of an env pin; the
581
+ // ps heuristic misfiles Claude Desktop as claude-code). Best-effort:
582
+ // attribution must never break a connection.
583
+ this.server.oninitialized = () => {
584
+ try {
585
+ const ci = this.server.getClientVersion?.();
586
+ if (ci?.name)
587
+ setMcpClientInfo(ci.name, ci.version);
588
+ }
589
+ catch { /* ignore */ }
590
+ };
577
591
  this.versionChecker = new RespiraVersionChecker('@respira/wordpress-mcp-server', RespiraWordPressServer.MCP_SERVER_VERSION);
578
592
  // RESPIRA_SITES env var: comma-separated hostnames to restrict visible sites.
579
593
  // Used by MCP config packs and multisite configurations.
@@ -1860,6 +1874,10 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
1860
1874
  type: 'string',
1861
1875
  description: 'URL slug (post_name). Example: "about-us" produces /about-us/.',
1862
1876
  },
1877
+ excerpt: {
1878
+ type: 'string',
1879
+ description: 'Post excerpt (wp_posts.post_excerpt) — the "Excerpt"/"Zajawka" panel, RSS summaries and archive teasers. Do NOT pass this inside meta: an excerpt written as post meta reads back fine and renders nowhere.',
1880
+ },
1863
1881
  custom_css: {
1864
1882
  type: 'string',
1865
1883
  description: 'Custom CSS for the page. Auto-detects builder: Divi → _et_pb_custom_css, Elementor → _elementor_page_settings.custom_css.',
@@ -2137,6 +2155,10 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
2137
2155
  type: 'string',
2138
2156
  description: 'URL slug (post_name). Example: "my-post" produces /my-post/.',
2139
2157
  },
2158
+ excerpt: {
2159
+ type: 'string',
2160
+ description: 'Post excerpt (wp_posts.post_excerpt) — the "Excerpt"/"Zajawka" panel, RSS summaries and archive teasers. Do NOT pass this inside meta: an excerpt written as post meta reads back fine and renders nowhere.',
2161
+ },
2140
2162
  author: {
2141
2163
  description: 'Author (user id or user login). Requires edit_others_posts capability when different from the acting user.',
2142
2164
  oneOf: [
@@ -4251,6 +4273,45 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
4251
4273
  },
4252
4274
  destructiveHint: true,
4253
4275
  },
4276
+ // Site Memory (v8.3, Resonance) — persistent per-site memory that lives IN the
4277
+ // WordPress site, so it travels across clients (Claude, ChatGPT, Cursor) and
4278
+ // sessions. Notes/preferences/lessons are advisory context; rules are ENFORCED
4279
+ // by the plugin (writes to protected content are refused server-side). The
4280
+ // current memory arrives automatically in get_site_context / get_builder_info
4281
+ // under the site_memory key.
4282
+ {
4283
+ name: 'wordpress_remember',
4284
+ description: "Save a durable memory about this site to its persistent Site Memory. Use when the user states a preference (\"always use native modules, never raw HTML\"), corrects a mistake worth not repeating, or you discover a convention or environment quirk the next session should know. The memory is injected into site context for every future agent session, across all AI clients. Ask the user before saving anything they did not state themselves. type=rule creates an ENFORCED constraint (with optional rule.protect post_ids/slugs the plugin will refuse to write to) that only the site owner can later remove. Re-using a key updates the entry. Included on Builder and Studio plans.",
4285
+ inputSchema: {
4286
+ type: 'object',
4287
+ properties: {
4288
+ key: { type: 'string', description: 'Short slug identifying the memory, e.g. "brand-voice" or "never-touch-checkout". Lowercase letters/digits/hyphens, max 64 chars. Re-using a key updates it.' },
4289
+ type: { type: 'string', enum: ['fact', 'preference', 'lesson', 'rule'], description: 'fact = observed setup; preference = user taste; lesson = learned from a mistake or correction; rule = enforced constraint (only the owner can remove it — use for "never touch X" instructions).' },
4290
+ content: { type: 'string', description: 'The memory itself, max 500 chars. Distill: one clear imperative sentence beats a paragraph.' },
4291
+ rule: { type: 'object', description: 'Rules only. {"protect":{"post_ids":[12],"slugs":["checkout"]}} makes the plugin refuse agent writes/deletes to that content, including its duplicates.' },
4292
+ builder: { type: 'string', description: 'Optional builder fingerprint (e.g. "bricks") when the memory is builder-specific, so staleness is detectable after a rebuild.' },
4293
+ builder_version: { type: 'string', description: 'Optional builder version for the fingerprint.' },
4294
+ },
4295
+ required: ['key', 'content'],
4296
+ },
4297
+ },
4298
+ {
4299
+ name: 'wordpress_forget',
4300
+ description: 'Remove a stale entry from this site\'s persistent Site Memory by key. Enforced rules cannot be removed from a conversation — only by the site owner in the Respira dashboard (Site Memory) — so a refusal here is expected behavior, not an error to work around.',
4301
+ inputSchema: {
4302
+ type: 'object',
4303
+ properties: {
4304
+ key: { type: 'string', description: 'Memory key to forget (from wordpress_list_memory).' },
4305
+ },
4306
+ required: ['key'],
4307
+ },
4308
+ },
4309
+ {
4310
+ name: 'wordpress_list_memory',
4311
+ description: 'List everything stored in this site\'s persistent Site Memory: facts, preferences, lessons, and enforced rules, with source and last-updated metadata. The same content arrives automatically in get_site_context; use this when you need keys for updating or forgetting entries.',
4312
+ inputSchema: { type: 'object', properties: {} },
4313
+ readOnlyHint: true,
4314
+ },
4254
4315
  {
4255
4316
  name: 'wordpress_list_custom_posts',
4256
4317
  description: 'List posts of a custom post type. Each row includes author ({id, login, display_name}), taxonomies map, and featured_media alongside id/title/slug/status/date/url.',
@@ -4424,6 +4485,10 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
4424
4485
  type: 'string',
4425
4486
  description: 'URL slug (post_name).',
4426
4487
  },
4488
+ excerpt: {
4489
+ type: 'string',
4490
+ description: 'Post excerpt (wp_posts.post_excerpt) — the "Excerpt"/"Zajawka" panel, RSS summaries and archive teasers. Do NOT pass this inside meta: an excerpt written as post meta reads back fine and renders nowhere.',
4491
+ },
4427
4492
  author: {
4428
4493
  description: 'Author (user id or user login). Requires edit_others_posts capability when different from the acting user.',
4429
4494
  oneOf: [
@@ -7261,6 +7326,13 @@ Allowlist: css, scss, less, json. PHP / JS theme writes are intentionally out of
7261
7326
  }
7262
7327
  case 'wordpress_delete_playbook':
7263
7328
  return await client.callRestV1('DELETE', `/playbooks/${args.id}`);
7329
+ // Site Memory (v8.3, Resonance)
7330
+ case 'wordpress_remember':
7331
+ return await client.callRestV1('POST', '/memory', { ...args, source: 'agent' });
7332
+ case 'wordpress_forget':
7333
+ return await client.callRestV1('DELETE', `/memory/${args.key}`);
7334
+ case 'wordpress_list_memory':
7335
+ return await client.callRestV1('GET', '/memory');
7264
7336
  case 'wordpress_list_custom_posts':
7265
7337
  return await client.listCustomPosts(args.type, args);
7266
7338
  case 'wordpress_get_custom_post':