@diviops/mcp-server 0.2.17 → 0.2.19

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/README.md CHANGED
@@ -9,7 +9,8 @@ Claude Code <-> MCP Server (stdio) <-> WordPress REST API <-> Divi MCP Plugin
9
9
  ## Requirements
10
10
 
11
11
  - **Node.js** >= 18.0.0
12
- - **WordPress** >= 5.6 (Application Passwords support)
12
+ - **PHP** >= 7.4
13
+ - **WordPress** >= 6.5
13
14
  - **Divi 5** theme active
14
15
  - **DiviOps Agent** WordPress plugin installed and active
15
16
 
@@ -175,6 +176,8 @@ Read-only commands plus non-destructive writes needed for core MCP functionality
175
176
  | Cache | `cache flush`, `transient delete`, `rewrite flush` |
176
177
  | Export | `export` (WXR data export to file) |
177
178
  | Info | `cron event list`, `plugin list`, `theme list`, `menu list`, `site url` |
179
+ | Core (read-only) | `core version`, `core check-update`, `core is-installed`, `core verify-checksums`, `core language list` |
180
+ | DB (introspection) | `db columns`, `db size`, `db tables`, `db check`, `db search` |
178
181
 
179
182
  ### Extended commands (opt-in)
180
183
 
@@ -2,7 +2,7 @@
2
2
  * Version compatibility between MCP server and WP plugin.
3
3
  */
4
4
  /** Minimum WP plugin version this server requires. */
5
- export declare const MIN_PLUGIN_VERSION = "1.0.0-beta.35";
5
+ export declare const MIN_PLUGIN_VERSION = "1.0.0-beta.36";
6
6
  /**
7
7
  * Compare two semver-like version strings (supports pre-release tags).
8
8
  *
@@ -2,7 +2,7 @@
2
2
  * Version compatibility between MCP server and WP plugin.
3
3
  */
4
4
  /** Minimum WP plugin version this server requires. */
5
- export const MIN_PLUGIN_VERSION = '1.0.0-beta.35';
5
+ export const MIN_PLUGIN_VERSION = '1.0.0-beta.36';
6
6
  /**
7
7
  * Compare two semver-like version strings (supports pre-release tags).
8
8
  *
package/dist/index.js CHANGED
@@ -726,7 +726,7 @@ server.registerTool("diviops_preset_create", {
726
726
  };
727
727
  });
728
728
  server.registerTool("diviops_preset_reassign", {
729
- description: 'Reassign a preset UUID across page content. Covers both module-level refs (`attrs.modulePreset[...]`) and attribute-level group-preset refs (`attrs.groupPreset.<slot>.presetId`), plus — for group presets — registry chain refs: module-bucket presets via top-level `groupPresets.<slot>.presetId`, group-bucket presets via `attrs.groupPreset.<slot>.presetId`. The `scope` param controls which ref types are walked (default "both", auto-selects based on new_uuid\'s bucket). Cross-bucket swaps (module ↔ group) are rejected. For module-scope swaps, optionally strips inline attrs that duplicate the new preset\'s attrs (otherwise inline wins over preset); slot-scoped inline strip for group scope is not yet implemented and is skipped with an advisory. Defaults to dry-run — set mode="apply" to actually rewrite. Use this to consolidate repeated inline styling into a reusable preset after creating one with diviops_preset_create.',
729
+ description: 'Reassign a preset UUID across page content. Covers both module-level refs (`attrs.modulePreset[...]`) and attribute-level group-preset refs (`attrs.groupPreset.<slot>.presetId`), plus — for group presets — registry chain refs: module-bucket presets via top-level `groupPresets.<slot>.presetId`, group-bucket presets via `attrs.groupPreset.<slot>.presetId`. The `scope` param controls which ref types are walked (default "both", auto-selects based on new_uuid\'s bucket). Cross-bucket swaps (module ↔ group) are rejected. When `strip_inline=true` (default), strips inline attrs that duplicate the new preset\'s attrs (otherwise inline wins over preset): for module scope, strips from block root; for group scope, strips per-slot using Divi\'s own slot→target-path resolver (handles composite button groups, `-id-classes` suffix, FormField/checkbox/radio `attrName` mappings, cross-module translation). Both scopes enforce a singular-stack guard (skip strip when slot holds multiple presets). Unmappable group slots skip strip and emit a per-slot advisory at `summary.strip_advisory_per_slot[<module>::<slot>]`; neighbor slots are unaffected. Defaults to dry-run — set mode="apply" to actually rewrite. Use this to consolidate repeated inline styling into a reusable preset after creating one with diviops_preset_create.',
730
730
  inputSchema: {
731
731
  old_uuid: z
732
732
  .string()
@@ -747,7 +747,7 @@ server.registerTool("diviops_preset_reassign", {
747
747
  .boolean()
748
748
  .optional()
749
749
  .default(true)
750
- .describe("If true (default), strip inline attrs that deep-equal the new preset's attrs so the preset actually takes effect. Applies to module-scope swaps only; group-scope swaps currently skip strip with an advisory in the summary. Set false to swap UUIDs only."),
750
+ .describe("If true (default), strip inline attrs that deep-equal the new preset's attrs so the preset actually takes effect. Applies to both module-scope (block-root strip) and group-scope (per-slot strip via Divi's target-path resolver). Singular-stack guard enforced at both scopes — strip is skipped when the modulePreset stack or a groupPreset slot holds multiple presets. Unmappable group slots skip strip with a per-slot advisory. Set false to swap UUIDs only."),
751
751
  scope: z
752
752
  .enum(["module", "group", "both"])
753
753
  .optional()
package/dist/wp-client.js CHANGED
@@ -5,6 +5,48 @@
5
5
  * Generate one at: WP Admin → Users → Your Profile → Application Passwords.
6
6
  */
7
7
  import { MIN_PLUGIN_VERSION, compareVersions, } from './compatibility.js';
8
+ /**
9
+ * Normalize over-escaped variable-token quote sequences inside `$variable(...)$`
10
+ * token regions only.
11
+ *
12
+ * Divi block-attrs JSON uses `\"` (2-byte) for inner quotes inside Divi variable
13
+ * tokens. Two over-escaped forms can leak in via callers that round-trip
14
+ * pre-existing broken bytes:
15
+ * - `\u0022` (11 bytes literal) — the mass-corruption form (backslash
16
+ * itself unicode-escaped, observed in the wild on Divi 5.3.x sites)
17
+ * - `\\u0022` (7 bytes literal) — produced when a caller passes the
18
+ * 6-byte `"` form through an extra JSON-encoding layer
19
+ *
20
+ * Both decode to the same value after Divi's resolver, but cause render asymmetry
21
+ * across attr paths (`background.color`, `spacing.margin`, `border.color`,
22
+ * `layout.columnGap` silently fail to resolve). We normalize defensively so any
23
+ * write — clean or pre-broken — settles on canonical bytes.
24
+ *
25
+ * Scope is intentionally narrow: rewrites only happen inside `$variable(...)$`
26
+ * regions (Divi's actual resolver boundary). Bytes outside those regions —
27
+ * arbitrary user text, code samples, string-variable values that happen to
28
+ * contain `\u0022` — are left untouched.
29
+ */
30
+ function normalizeQuoteEscapes(s) {
31
+ return s.replace(/\$variable\([^$]*?\)\$/g, (token) => token.replace(/(?:\\u005cu0022|\\\\u0022)/g, '\\"'));
32
+ }
33
+ function normalizeBody(value) {
34
+ if (typeof value === 'string')
35
+ return normalizeQuoteEscapes(value);
36
+ if (Array.isArray(value))
37
+ return value.map(normalizeBody);
38
+ // Restrict recursion to plain objects so Date / RegExp / class instances
39
+ // with custom `toJSON` keep their canonical serialization.
40
+ if (value &&
41
+ typeof value === 'object' &&
42
+ Object.getPrototypeOf(value) === Object.prototype) {
43
+ const out = {};
44
+ for (const [k, v] of Object.entries(value))
45
+ out[k] = normalizeBody(v);
46
+ return out;
47
+ }
48
+ return value;
49
+ }
8
50
  export class WPClient {
9
51
  baseUrl;
10
52
  authHeader;
@@ -34,7 +76,7 @@ export class WPClient {
34
76
  },
35
77
  };
36
78
  if (body && method !== 'GET') {
37
- fetchOptions.body = JSON.stringify(body);
79
+ fetchOptions.body = JSON.stringify(normalizeBody(body));
38
80
  }
39
81
  const response = await fetch(url, fetchOptions);
40
82
  if (!response.ok) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diviops/mcp-server",
3
- "version": "0.2.17",
3
+ "version": "0.2.19",
4
4
  "description": "MCP server exposing Divi 5 Visual Builder as tools for Claude",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",