@diviops/mcp-server 1.4.1 → 1.5.2

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
@@ -1,367 +1,184 @@
1
- # Divi 5 MCP Server
1
+ # DiviOps MCP Server
2
2
 
3
- MCP server that exposes Divi 5 Visual Builder operations as tools for Claude Code and Claude Desktop.
3
+ **AI-driven WordPress site authoring Divi-native, with the rest of WP in scope.**
4
+
5
+ Programmatic site authoring through Claude Code, Claude Desktop, and any other MCP client. Built on Divi 5 as the page authoring foundation, the suite also handles WordPress data models — custom post types, Secure Custom Fields, taxonomies, site audits, and hybrid sites where Divi authors the marketing pages and custom PHP templates handle the dynamic ones, with design tokens harmonized across both surfaces. Pairs with a WordPress companion plugin and ships alongside a Claude skill that knows the Divi 5 block format.
4
6
 
5
7
  ```
6
- Claude Code <-> MCP Server (stdio) <-> WordPress REST API <-> Divi MCP Plugin
8
+ Claude Code <-> MCP Server (stdio) <-> WordPress REST API <-> DiviOps Agent plugin
7
9
  ```
8
10
 
9
- ## Requirements
11
+ ## Use cases
10
12
 
11
- - **Node.js** >= 18.0.0
12
- - **PHP** >= 7.4
13
- - **WordPress** >= 6.5
14
- - **Divi 5** theme active
15
- - **DiviOps Agent** WordPress plugin installed and active
13
+ DiviOps fits multiple WordPress workflows where AI-driven authoring + management is the value:
16
14
 
17
- ## Setup
15
+ - **Page building (Divi authoring)** — create + edit Divi pages, sections, modules, canvases via prompt; preset-driven design system reuse; Theme Builder layouts and templates.
16
+ - **SCF setup + management** — provision Secure Custom Fields field groups, sync schemas, export/import field group definitions; SCF data model becomes a tool surface, not an admin-UI flow.
17
+ - **CPT + post population** — register custom post types via wp-cli passthrough; bulk-populate posts and pages across any post type, not just Divi-built ones.
18
+ - **Data model reasoning** — schema introspection across Divi modules + SCF field groups + post meta; ask Claude what fields a post type carries, what attributes a module accepts, what tokens are defined.
19
+ - **WordPress site auditing** — preset audits, design-token usage scans, orphan detection (presets, variables, dangling references); broader site surveys via wp-cli (`wp option list`, `wp post list --format=json`, `wp user list`).
20
+ - **Hybrid sites (Divi + custom PHP)** — Divi authors the marketing pages; custom PHP templates handle dynamic ones (CPT listings, single-post views, member portals); design tokens harmonized across both surfaces via CSS custom properties driven from the Divi variable system.
18
21
 
19
- ### 1. Install the WordPress Plugin
22
+ ## Quick start
20
23
 
21
- Download and activate the **DiviOps Agent** plugin — [direct zip](https://github.com/oaris-dev/diviops/raw/main/diviops-agent.zip) or browse the [public distribution repo](https://github.com/oaris-dev/diviops).
24
+ Three steps to your first tool call.
22
25
 
23
- ### 2. Create an Application Password
24
-
25
- Go to **WP Admin -> Users -> Your Profile -> Application Passwords**:
26
- - Enter a name (e.g., "MCP Server")
27
- - Click "Add New Application Password"
28
- - Copy the generated password
26
+ ### 1. Install the WordPress plugin
29
27
 
30
- > **Tip:** Strip spaces from Application Passwords before use. WordPress generates them with spaces for readability but accepts them without. Spaces in shell commands can cause parsing issues.
28
+ Download and activate the **DiviOps Agent** plugin [direct zip](https://github.com/oaris-dev/diviops/raw/main/diviops-agent.zip) or browse the [public distribution repo](https://github.com/oaris-dev/diviops). Requires Divi 5.1+ on WordPress 6.5+.
31
29
 
32
- ### 3. Configure Claude Code
30
+ ### 2. Create an Application Password
33
31
 
34
- ```bash
35
- claude mcp add diviops-mcp \
36
- --env WP_URL=http://your-site.local \
37
- --env WP_USER=your-wp-username \
38
- --env WP_APP_PASSWORD=xxxxXXXXxxxxXXXXxxxxXXXX \
39
- -- npx @diviops/mcp-server
40
- ```
32
+ In **WP Admin → Users → Your Profile → Application Passwords**:
33
+ - Enter a name (e.g. "MCP Server")
34
+ - Click "Add New Application Password"
35
+ - Copy the generated password and strip the spaces
41
36
 
42
- > **Use `--env` flags, not the `env` command.** Claude Code's native `--env KEY=VALUE` flags survive copy-paste; the older `-- env KEY=VALUE` form (piping through unix `env`) breaks silently when any value contains a space. Quote any value with spaces (e.g. `--env "WP_PATH=/Users/you/Local Sites/site/app/public"`) — no backslash escaping needed inside quotes.
37
+ ### 3. Register the MCP server with Claude
43
38
 
44
- **With WP-CLI** (optional — enables `diviops_meta_wp_cli` tool):
45
39
  ```bash
46
40
  claude mcp add diviops-mcp \
47
41
  --env WP_URL=http://your-site.local \
48
42
  --env WP_USER=your-wp-username \
49
43
  --env WP_APP_PASSWORD=xxxxXXXXxxxxXXXXxxxxXXXX \
50
- --env "WP_PATH=/path/to/wordpress" \
51
- -- npx @diviops/mcp-server
52
- ```
53
-
54
- **With Docker-based WP-CLI** (optional — uses a custom command prefix):
55
- ```bash
56
- claude mcp add diviops-mcp \
57
- --env WP_URL=https://site-name.ddev.site \
58
- --env WP_USER=your-wp-username \
59
- --env WP_APP_PASSWORD=xxxxXXXXxxxxXXXXxxxxXXXX \
60
- --env "WP_CLI_CMD=ddev wp" \
61
- -- npx @diviops/mcp-server
62
- ```
63
-
64
- ### Environment Variables
65
-
66
- | Variable | Required | Description |
67
- |----------|----------|-------------|
68
- | `WP_URL` | Yes | WordPress site URL (e.g. `http://mysite.local`) |
69
- | `WP_USER` | Yes | WordPress username with Editor or Admin role |
70
- | `WP_APP_PASSWORD` | Yes | Application Password (spaces stripped) |
71
- | `WP_PATH` | No | WordPress filesystem path for Local by Flywheel, or wrapper working directory when `WP_CLI_CMD` needs project context |
72
- | `WP_CLI_CMD` | No | Custom WP-CLI command prefix for containerized environments, e.g. `ddev wp`, `npx wp-env run cli wp`, `docker exec -u www-data devkinsta_fpm wp --path=/www/kinsta/public/sitename` |
73
- | `LOCAL_SITE_ID` | No | Override auto-detection of Local by Flywheel site ID |
74
- | `DIVIOPS_WP_CLI_ALLOW` | No | Comma-separated list of extended WP-CLI commands to enable (see [WP-CLI Security](#wp-cli-security)) |
75
- | `DIVIOPS_WP_CLI_SAFE_FS_ROOT` | No | Absolute path to constrain filesystem-touching commands (`wp export`, `acf export/import`). Defaults to `<WP_PATH>/.diviops-tmp/` in host mode. **Required** in `WP_CLI_CMD` wrapper mode (must be the container-namespace path, since the host path can't be inferred) |
76
- | `DIVIOPS_WP_CLI_UNSAFE_FS` | No | Set to `1` to disable filesystem flag validation entirely. For trusted single-user local-dev setups where the `--dir` / positional-path safety checks get in the way |
77
-
78
- ### Local Development Environments
79
-
80
- The server connects via standard WordPress REST API and works with any environment that exposes WordPress over HTTP with Application Password support.
81
-
82
- | Environment | WP_URL | WP-CLI setup | Notes |
83
- |-------------|--------|--------------|-------|
84
- | **Local by Flywheel** | `http://site-name.local` | `WP_PATH=/path/to/site/app/public` | Site ID auto-detected, fully supported |
85
- | **WordPress Studio** | `http://localhost:{port}` | `WP_CLI_CMD="studio wp --path=/path/to/site"` | Port auto-assigned (8881, 8882, ...). Uses SQLite, not MySQL |
86
- | **DDEV** | `https://site-name.ddev.site` | `WP_CLI_CMD="ddev wp"` plus `WP_PATH=/path/to/project` | Wrapper runs from `WP_PATH` so DDEV can resolve the site |
87
- | **wp-env** | `http://localhost:8888` | `WP_CLI_CMD="npx wp-env run cli wp"` plus `WP_PATH=/path/to/project` | Wrapper runs from `WP_PATH`; requires `WP_ENVIRONMENT_TYPE=local` (see below) |
88
- | **DevKinsta** | `https://site-name.local` | `WP_CLI_CMD="docker exec -u www-data devkinsta_fpm wp --path=/www/kinsta/public/sitename"` | HTTPS with self-signed certs |
89
- | **Custom / Remote** | Your site URL | `WP_PATH=/path/to/site` or `WP_CLI_CMD="..."` | Works with any WP host |
90
-
91
- > **Application Passwords on HTTP:** WordPress requires HTTPS for Application Passwords unless `WP_ENVIRONMENT_TYPE` is set to `'local'`. HTTPS environments (DDEV, DevKinsta) work out of the box. HTTP environments (wp-env, WordPress Studio) need this in `wp-config.php`:
92
- > ```php
93
- > define('WP_ENVIRONMENT_TYPE', 'local');
94
- > ```
95
- > Local by Flywheel sets this automatically.
96
-
97
- > **WP-CLI note:** `WP_PATH` keeps the existing Local by Flywheel behavior by running `wp` directly on the host filesystem. For Docker-based environments (DDEV, wp-env, DevKinsta, WordPress Studio), set `WP_CLI_CMD` to the wrapper command instead. When `WP_CLI_CMD` is set, the server executes the wrapper from `WP_PATH` if provided, otherwise from its current working directory. The MCP server still validates the requested WP-CLI subcommand against its allowlist before executing either path.
98
-
99
- ## Available Tools (66)
100
-
101
- ### Read (30)
102
- | Tool | Description |
103
- |------|-------------|
104
- | `diviops_meta_ping` | Test WordPress connection and Divi version |
105
- | `diviops_meta_info` | DiviOps server identity, version, license type, capabilities |
106
- | `diviops_page_list` | List pages/posts with Divi status |
107
- | `diviops_page_get` | Get page details and raw content |
108
- | `diviops_page_get_layout` | Get parsed block tree (layout structure) |
109
- | `diviops_section_get` | Get a single section's markup by admin label |
110
- | `diviops_schema_list_modules` | List all available Divi modules |
111
- | `diviops_schema_get_module` | Get attribute schema for a module. Default `mode: "single"` returns one module's schema (optimized; `raw: true` for full). `mode: "dump_all"` snapshots every Divi module in one call along with a `schema_version` hash over `*PresetAttrsMap.php` and a `divi_version` field — build-time entry point for the skill regen pipeline. |
112
- | `diviops_schema_get_settings` | Get Divi site settings and theme options |
113
- | `diviops_global_color_list` | Get global color palette |
114
- | `diviops_global_font_list` | Get global font definitions |
115
- | `diviops_meta_find_icon` | Search 1,989 icons by keyword (FA + Divi) |
116
- | `diviops_template_list` | List available MCP prompt templates |
117
- | `diviops_template_get` | Get a specific template's block markup |
118
- | `diviops_preset_audit` | Audit presets with referenced/unreferenced analysis. Walks both page content and in-registry `groupPresets` chains; exposes `block_ref_count`, `group_ref_count`, `referenced_by_presets`. Also reports `orphan_default_pointers` — per-bucket `default` pointers referencing UUIDs missing from `items[]` (legacy damage from past unsafe deletes; clear via `diviops_preset_set_default` in bucket-addressed mode: `type` + `module` + `unset=true`) |
119
- | `diviops_preset_scan_orphans` | List page-referenced preset UUIDs missing from the D5 registry (separates dangling orphans from D4-legacy refs) |
120
- | `diviops_library_list` | List saved Divi Library items |
121
- | `diviops_library_get` | Get a library item's block markup |
122
- | `diviops_render_preview` | Render block markup to HTML for preview |
123
- | `diviops_validate_blocks` | Validate block markup (structure, required attrs, known pitfalls) |
124
- | `diviops_tb_template_list` | List Theme Builder templates with conditions and layout IDs |
125
- | `diviops_tb_layout_get` | Get a Theme Builder layout's block markup (header/body/footer) |
126
- | `diviops_variable_list` | List design token variables (filter by type or prefix) |
127
- | `diviops_variable_scan_orphans` | Find `gvid-`/`gcid-` refs with no backing Variable Manager entry (orphans render as invalid CSS) + unused variables (defined, never referenced). Scans pages, Theme Builder layouts (header/body/footer), Divi Library items, canvas pages, and the preset registry |
128
- | `diviops_variable_used_on_page` | Detect which `gvid-` (numeric/font) IDs a single page emits — the exact set Divi 5.4.0+ uses to scope selective `:root{--gvid-*}` CSS variable emission. Walks the same content stack the frontend assembles (post_content + active TB header/body/footer + appended canvases + presets). `gcid-` colors are out of scope (separate emission path). Use for per-page orphan validation, preflight before bulk variable rename, or to debug why a numeric/font variable doesn't render on a specific page. Read-only |
129
- | `diviops_canvas_list` | List all canvas pages |
130
- | `diviops_canvas_get` | Get canvas content |
131
- | `diviops_scf_status` | Show SCF (Secure Custom Fields) sync status — pending JSON-vs-DB drift across field groups, post types, taxonomies, options pages. Wraps `wp scf json status` |
132
- | `diviops_scf_field_group_list` | List all SCF/ACF field groups (post_name = ACF key, post_title, post_status, post_modified). Queries the `acf-field-group` post type via `wp post list` (works on SCF 6.8.4+ and older ACF) |
133
- | `diviops_scf_field_group_get` | Fetch a single SCF/ACF field-group post by ACF key (`group_abc123` → post_name) or numeric WP post ID. For the parsed/structured field tree, use `diviops_scf_export --field-groups=<key> --stdout` |
134
-
135
- ### Write (34)
136
- | Tool | Description |
137
- |------|-------------|
138
- | `diviops_page_create` | Create a new page with optional Divi content |
139
- | `diviops_page_update_content` | Full page content rewrite |
140
- | `diviops_page_trash` | Trash (default) or permanently delete (`force=true`) a page. Idempotent on already-trashed posts. Supports `dry_run` |
141
- | `diviops_page_update_status` | Update post_status (publish/draft/private/pending/future). `future` requires `date_gmt` (ISO 8601 UTC); `publish` clears stale future dates so re-publishing takes effect immediately. Supports `dry_run` |
142
- | `diviops_section_append` | Append a section to existing page (start or end) |
143
- | `diviops_section_replace` | Replace a section by admin label |
144
- | `diviops_section_remove` | Remove a section by admin label |
145
- | `diviops_module_update` | Update specific module attributes by label or text match |
146
- | `diviops_module_move` | Move a block before/after another block (reorder modules, sections) |
147
- | `diviops_module_lock` | Lock a module so VB users cannot edit it (frontend renders normally) |
148
- | `diviops_module_unlock` | Unlock a module by removing `attrs.locked` (matches VB's absence convention) |
149
- | `diviops_module_clone` | Deep-copy a module + insert next to source within the same parent |
150
- | `diviops_global_color_create` | Add a new global color to Divi's palette (writes canonical shape; closes ET's bundle Zod gap that drops `label`) |
151
- | `diviops_global_color_update` | Update an existing global color by gcid (only provided fields change) |
152
- | `diviops_global_color_delete` | Delete a global color (refuses if `usedInPosts` non-empty unless `force=true`; customizer-bound defaults always protected) |
153
- | `diviops_preset_cleanup` | Remove spam/duplicate presets, bulk rename |
154
- | `diviops_preset_create` | Write a new preset to the D5 registry (module or group type, supports `divi/column` etc.). Optional `make_default: true` sets it as the bucket's default; optional `priority` controls stack-merge order |
155
- | `diviops_preset_reassign` | Rewrite `modulePreset` references across pages (dry-run by default; optional `strip_inline` removes redundant inline attrs) |
156
- | `diviops_preset_update` | Update a specific preset (name, attrs, priority) |
157
- | `diviops_preset_delete` | Delete a preset by ID. Refuses with HTTP 409 `preset_is_default` when the target is the registered default for its bucket — clear the pointer first via `diviops_preset_set_default` with `unset=true`, or pass `force=true` to delete and clear the pointer in one write |
158
- | `diviops_preset_set_default` | Set or clear the per-module/group default preset. Two modes: by `preset_id` (UUID-addressed; auto-resolves bucket) or by `type` + `module` + `unset=true` (bucket-addressed clear, used to repair orphan default pointers when the UUID is gone from `items[]`). Defaults apply to NEW instances only — use `diviops_preset_reassign` for retroactive swaps |
159
- | `diviops_library_save` | Save block markup to Divi Library |
160
- | `diviops_tb_layout_update` | Update a Theme Builder layout's block markup |
161
- | `diviops_tb_template_create` | Create Theme Builder template with header/footer and conditions |
162
- | `diviops_variable_create` | Create a design token variable. For `type=numbers` fluid tokens, pass `min`+`max` shorthand (anchors default to 320px/1920px) or explicit `targets` like `{"320px":"20px","1920px":"60px"}` — server generates arithmetically-correct `clamp()` instead of hand-written math that silently under-reaches the stated max. All-px inputs emit px (root-agnostic). Rem inputs OR rem output require explicit opt-in: pass `output_unit="rem"` (accepts the 1rem=16px default) or `root_font_size_px:N` (declares your site's actual root font-size, e.g. `10` for `html { font-size: 62.5% }`, `20` for `html { font-size: 20px }`) |
163
- | `diviops_variable_create_fluid_system` | Batch-emit a fluid typography + spacing + radius variable set in one call. Mirrors Divi 5.4.0's Variable Generator Modal at the algorithm level (clamp() math is identical to `diviops_variable_create`'s fluid mode) but layers profile-selectable anchors over it: `divi-default` (360→1350) matches ET's defaults, `wide` (320→1920) matches the diviops convention, `custom` takes explicit anchors. Each category is independent and optional. Typography uses modular-scale chains (named ratios `major-third`/`perfect-fifth`/`golden`/etc., or raw numbers) — h1 = largest, hN = base. Spacing/radius support `linear` or `geometric` step distributions. `dry_run: true` returns the full plan without persisting; `overwrite: false` (default) skips existing IDs. Single atomic write to the registry — mid-batch failures roll back cleanly |
164
- | `diviops_variable_delete` | Delete a variable by ID. Returns HTTP 409 when live references exist unless `force=true` (use `diviops_variable_scan_orphans` to find reference locations). Returns HTTP 403 for Divi's customizer-bound defaults (`gcid-primary-color`, `gcid-secondary-color`, `gcid-heading-color`, `gcid-body-color`, `gcid-link-color` — managed via WP Customizer) |
165
- | `diviops_canvas_create` | Create a canvas page |
166
- | `diviops_canvas_duplicate` | Deep-copy a canvas (content + canvas-specific meta). Default copy title `<source> (Copy)` auto-suffixes on collision (Copy 2, …); explicit `title` collisions return 409. Supports `dry_run` |
167
- | `diviops_canvas_update` | Update canvas content and/or metadata. Pass any subset of fields — `{canvas_post_id, title}` renames without touching content |
168
- | `diviops_canvas_delete` | Delete a canvas page |
169
- | `diviops_scf_export` | Export SCF schema (field groups, post types, taxonomies, options pages) as JSON to a directory under the safe-root, or to stdout. Wraps `wp scf json export` |
170
- | `diviops_scf_import` | Import SCF schema from a JSON file (mutates DB; idempotent — existing items are updated). Wraps `wp scf json import <file>` |
171
- | `diviops_scf_sync` | Apply pending JSON-on-disk SCF changes to the DB. Defaults to `dry_run: true` for safety. Wraps `wp scf json sync` |
172
-
173
- ### Utility (2)
174
- | Tool | Description |
175
- |------|-------------|
176
- | `diviops_meta_wp_cli` | Run WP-CLI commands (allowlisted, requires `WP_PATH` or `WP_CLI_CMD`) |
177
- | `diviops_meta_flush_cache` | Flush Divi's compiled CSS cache under `wp-content/et-cache/`. `wp cache flush` does NOT touch these files — the frontend can keep serving stale CSS after mutations. Delegates to Divi's native clearer (`ET_Core_PageResource::remove_static_resources`) when available — also clears Theme Builder / archive / taxonomy / home / notfound CSS, object cache, module features cache, post features cache, dynamic assets cache, Google Fonts cache, post meta caches. Falls back to a filesystem walk of numeric-named subdirs when Divi is inactive. Response includes `backend: "divi_native"` or `"fs_fallback"`. Exactly one selector required: `post_id`, `all`, or `after` (unix ts) — no default to `all` |
178
-
179
- ## WP-CLI Security
180
-
181
- The `diviops_meta_wp_cli` tool validates every command against a safety allowlist before execution. Commands not on the list are rejected.
182
-
183
- ### Default allowlist (always available)
184
-
185
- Read-only commands plus non-destructive writes needed for core MCP functionality and local development workflows:
186
-
187
- | Category | Commands |
188
- |----------|----------|
189
- | Options | `option get`, `option list` |
190
- | Posts | `post list`, `post get`, `post create`, `post update` |
191
- | Post meta | `post meta get`, `post meta list`, `post meta set`, `post meta update` |
192
- | Post types | `post-type list`, `post-type get` |
193
- | Taxonomies | `taxonomy list`, `term list`, `term create`, `term update` |
194
- | ACF / SCF | `acf export`, `acf import`, `acf field-group list`, `acf field-group get`, `scf json {status,sync,import,export}` (also aliased as `acf json …` per SCF 6.8.4+) |
195
- | Users | `user list` |
196
- | Cache | `cache flush`, `transient delete`, `rewrite flush` |
197
- | Export | `export` (WXR data export to file) |
198
- | Info | `cron event list`, `plugin list`, `theme list`, `menu list`, `site url` |
199
- | Core (read-only) | `core version`, `core check-update`, `core is-installed`, `core verify-checksums`, `core language list` |
200
- | DB (introspection) | `db columns`, `db size`, `db tables`, `db check`, `db search` |
201
-
202
- ### Extended commands (opt-in)
203
-
204
- These commands carry higher risk and require explicit opt-in via the `DIVIOPS_WP_CLI_ALLOW` environment variable:
205
-
206
- | Command | Risk | Why opt-in |
207
- |---------|------|------------|
208
- | `option update` | High | Can change site URL, admin email, or security settings |
209
- | `option delete` | High | Permanently removes a WP option (no undo) |
210
- | `post delete` | Medium | Permanently removes content |
211
- | `post meta delete` | Medium | Removes metadata |
212
- | `term delete` | Medium | Permanently removes taxonomy terms |
213
- | `search-replace` | High | Bulk database modification — can corrupt content if misused |
214
- | `import` | Medium | Bulk content ingestion from WXR files |
215
- | `plugin activate` | Medium | Can enable untrusted plugins |
216
- | `plugin deactivate` | Medium | Can disable security plugins |
217
- | `eval-file` | Critical | Executes arbitrary PHP from a file path |
218
-
219
- To enable extended commands, add `DIVIOPS_WP_CLI_ALLOW` to your MCP registration:
220
-
221
- ```bash
222
- claude mcp add diviops-mcp \
223
- --env WP_URL=http://your-site.local \
224
- --env WP_USER=admin \
225
- --env WP_APP_PASSWORD=xxxx \
226
- --env "WP_PATH=/path/to/wordpress" \
227
- --env "DIVIOPS_WP_CLI_ALLOW=option update,post delete,search-replace" \
228
44
  -- npx @diviops/mcp-server
229
45
  ```
230
46
 
231
- Only list the specific commands you need. Unknown entries are ignored with a warning.
232
-
233
- #### Wildcard / "god-mode" (local dev only)
234
-
235
- For trusted local-dev environments where you don't want to re-list every extended command per site, the values `*` and `all` grant the full extended set:
236
-
237
- ```bash
238
- --env "DIVIOPS_WP_CLI_ALLOW=*"
239
- ```
240
-
241
- The sentinel grants exactly the extended set above — it does NOT unlock anything beyond it (notably: `db query` stays out by design). The server emits a startup warning to stderr whenever the wildcard is active, so the broad grant is never silent. Auto-adopts new extended commands on future versions.
242
-
243
- > **Don't use this in shared or production environments.** Pin the specific commands you need with the comma-separated form instead.
47
+ Then ask Claude: **"List the pages on my site."** Claude calls `diviops_page_list` and renders the result. You're authoring with the suite.
244
48
 
245
- > **Note on `acf import`**: included in the default allowlist because it's an idempotent dev-time schema operation (re-creates field groups from JSON). Bulk content imports use `wp import` instead, which is opt-in.
49
+ For a deeper walkthrough (containerized environments, WP-CLI configuration, troubleshooting installation), see [setup-guide.md](../docs/setup-guide.md).
246
50
 
247
- ### Filesystem flag validation
51
+ ## Example workflow
248
52
 
249
- The DEFAULT-tier filesystem commands (`wp export`, `acf export <path>`, `acf import <path>`, `scf json export --dir=<path>`, `scf json import <file>`, plus the `acf json …` aliases) are second-pass validated against a safe root so wrong-path arguments can't write WXR / schema JSON to the web root or read configs from arbitrary locations.
53
+ > **You:** Create a hero section on a new page called "Spring Launch" with a heading, subheading, and a CTA button. Use my brand colors.
250
54
 
251
- - **Safe root**: `<WP_PATH>/.diviops-tmp/` by default (auto-created on first use in host mode). Override with `DIVIOPS_WP_CLI_SAFE_FS_ROOT=/absolute/path`. All path arguments must canonicalize under this directory; symlinks are resolved via `realpath` so a planted symlink inside the safe root pointing outside it is caught.
252
- - **`wp export` must pass `--dir=<path-under-safe-root>`** (or `--stdout`). Without `--dir`, wp-cli writes to the current working directory; on prod that's typically the web root.
253
- - **`--filename_format=` must be a filename template**, not a path — separators (`/`, `\`) are rejected so a crafted template can't escape `--dir`'s scope.
254
- - **`acf export/import`'s positional path** must resolve under the safe root.
255
- - **`scf json export`'s `--dir=` flag** must resolve under the safe root (or pass `--stdout` for in-memory transfer). **`scf json import`'s positional `<file>` path** must resolve under the safe root.
256
- - **Wrapper mode (`WP_CLI_CMD`)**: the host-derived safe root doesn't correspond to the wrapper's filesystem (e.g., container paths like `/www/app`), so `DIVIOPS_WP_CLI_SAFE_FS_ROOT` is **required** and must be set to the container-namespace path. FS-sensitive commands are rejected with a clear error if it's missing.
257
- - **Escape hatch**: `DIVIOPS_WP_CLI_UNSAFE_FS=1` disables validation entirely. Appropriate for trusted single-user local-dev setups that don't want the guard.
55
+ Claude orchestrates a few tool calls in sequence:
258
56
 
259
- **EXTENDED-tier filesystem commands** (`import`, `eval-file`) are not flag-validated here opt-in via `DIVIOPS_WP_CLI_ALLOW` signals the caller has accepted the path-scope risk. That constraint is a candidate future enhancement if the MCP server ships in multi-tenant contexts.
57
+ 1. `diviops_global_color_list` — discovers your brand palette.
58
+ 2. `diviops_template_list` / `diviops_template_get` — pulls a verified hero template that matches the request.
59
+ 3. `diviops_page_create` — creates `Spring Launch` as a draft with the hero block markup.
60
+ 4. `diviops_validate_blocks` — confirms the markup is well-formed before save.
61
+ 5. `diviops_render_preview` — returns the rendered HTML so you can verify before publishing.
260
62
 
261
- ## Safety Patterns
63
+ The skill enforces the Divi block format, the design system, and the response contract throughout — you stay at the prompt level.
262
64
 
263
- High-risk or bulk destructive tools follow one of two conventions to guard against unintended mutation. Both are stateless (no session tokens between calls), but they guard differently: Pattern A is a **stateless gate** — the first call mutates when the safety check passes, refuses with an explanatory error when it fires. Pattern B is **preview-before-commit** — the first call never mutates; an explicit apply step is required. Tools without a gate (e.g., `diviops_page_update_content`) execute their mutation directly — whether to adopt a pattern is a per-tool design decision, not a retrofit requirement.
65
+ ## Tools at a glance
264
66
 
265
- ### Pattern A `force: false/true` (refuse-with-override)
67
+ The server exposes **66 tools** across the categories below. Each category links to representative tools; the full table lives in [server-reference.md](../docs/server-reference.md).
266
68
 
267
- Tool refuses the operation with an explanatory error when a safety check fails; caller reviews the reason and retries with `force=true` to commit. Single round-trip on the happy path, single retry on the override path.
69
+ | Category | Use case | Tool prefixes |
70
+ |----------|----------|---------------|
71
+ | Page authoring | Create, edit, restructure pages | `page_*`, `section_*`, `module_*` |
72
+ | Design system | Manage colors, fonts, variables, presets | `variable_*`, `global_color_*`, `global_font_*`, `preset_*` |
73
+ | Library + templates | Reusable layouts + Theme Builder | `library_*`, `template_*`, `tb_*` |
74
+ | Schema introspection | Module attribute discovery | `schema_*` |
75
+ | Canvas / off-canvas | Popups, modals, menus | `canvas_*` |
76
+ | SCF integration | Secure Custom Fields sync | `scf_*` |
77
+ | Render + validate | Preview HTML, validate block markup | `render_preview`, `validate_blocks` |
78
+ | WP-CLI passthrough | Escape hatch for site ops | `meta_wp_cli` |
79
+ | Cache + meta | Connection probe, identity, icons, cache flush | `meta_*` |
268
80
 
269
- **Fit criteria:**
270
- - Operation targets a **single item** (one variable, one preset, one page)
271
- - Safety check is **binary** (safe / not safe)
272
- - The reason for blocking is compact enough to fit in the error body (e.g., "3 live references")
273
- - The caller can decide from the error alone — no full diff needed
81
+ See [server-reference.md](../docs/server-reference.md) for per-tool descriptions.
274
82
 
275
- **Current tools:**
276
- | Tool | Guard | Override |
277
- |------|-------|----------|
278
- | `diviops_variable_delete` | HTTP 409 when live references exist | `force=true` |
279
- | `diviops_preset_delete` | HTTP 409 `preset_is_default` when target is the registered default for its bucket | `force=true` (deletes + clears the `default` pointer in the same write) |
83
+ ## Response contract
280
84
 
281
- ### Pattern B `mode: "dry-run"/"apply"` (preview-then-commit)
85
+ Tools return a standardized envelope. The shape lets clients branch on `ok` and machine-readable `error.code` without parsing freeform messages.
282
86
 
283
- Tool returns a preview of the changes it would make; caller reviews the diff, then re-invokes with the apply flag to commit. Two round-trips by design — the preview itself is the value.
284
-
285
- **Fit criteria:**
286
- - Operation touches **many items** (bulk reassign, bulk cleanup)
287
- - The *preview is the value* caller wants the full list of changes before committing
288
- - Side effects don't fit in a one-line reason (e.g., "142 preset refs across 18 pages rewritten from UUID X to UUID Y")
289
- - Two round-trips are acceptable because the caller is already in review mode
290
-
291
- **Current tools:**
292
- | Tool | Preview flag | Commit flag |
293
- |------|--------------|-------------|
294
- | `diviops_preset_reassign` | `mode: "dry-run"` (default) | `mode: "apply"` |
295
- | `diviops_preset_cleanup` | `dry_run: true` (default) | `dry_run: false` |
296
-
297
- > Both preview-then-commit tools share the same semantic pattern but use different parameter shapes (`mode` enum vs `dry_run` bool). Both predate this convention and stay as-is for caller compatibility. **New bulk tools should use the enum form** (`mode: "dry-run" | "apply"`) — it's more extensible if future modes are needed (`"interactive"`, `"selective"`, etc.) and keeps the interface consistent as the tool set grows.
298
-
299
- ### Pattern B (variant) — universal `dry_run: boolean` on every write tool
300
-
301
- Every mutating tool also accepts an optional `dry_run: boolean` (default `false`). When `true`, the response carries a uniform plan shape — `{ ok: true, data: { dry_run: true, plan: { summary, changes[, warnings] } } }` — and no state is mutated. Apply mode (`dry_run` omitted) keeps each tool's pre-existing response shape unchanged, so adding the parameter is non-breaking.
87
+ ```jsonc
88
+ // Success
89
+ { "ok": true, "data": <payload> }
90
+ // Failure
91
+ { "ok": false, "error": { "code": "<code>", "message": "<human>", "hint": "<optional>" } }
92
+ ```
302
93
 
303
- This complements Pattern B's `mode: dry-run/apply` convention on bulk operations:
304
- - `mode: "dry-run"/"apply"` is the explicit two-round-trip contract for bulk tools where the preview *is* the value.
305
- - `dry_run: true` is the lighter "preview before commit" knob available on every write tool, including single-item ones.
94
+ ### Standard error codes
95
+
96
+ | code | HTTP | meaning |
97
+ |---|---|---|
98
+ | `not_found` | 404 | Target ID does not resolve |
99
+ | `invalid_input` | 400 | Schema violation, malformed args |
100
+ | `validation_failed` | 400 | `validate_blocks`-detected shape error |
101
+ | `conflict` | 409 | Uniqueness collision |
102
+ | `forbidden` | 403 | Row-level WordPress auth signal |
103
+ | `capability_missing` | 412 | Plugin version below required for this tool |
104
+ | `wp_error` | 500 | Underlying WordPress error |
105
+ | `divi_error` | 500 | Divi-specific error (block parser, validator, etc.) |
106
+
107
+ ### Namespace-specific codes
108
+
109
+ Namespaces extend the vocabulary using the `<namespace>.<reason>` convention — e.g. `meta_wp_cli.command_failed`, `scf.not_configured`, `preset.bucket_mismatch`, `variable.customizer_default_immutable`. Namespace-prefixed codes carry structured `error.data` documenting the failure (exit codes, conflicting fields, reference counts, etc.). Per-tool descriptions name the codes each tool emits and the `error.data` shape that accompanies them.
110
+
111
+ ### `dry_run` plan shape
112
+
113
+ Every write tool accepts `dry_run: boolean` (default `false`). When `true`, the response carries a uniform plan shape and no state is mutated:
114
+
115
+ ```json
116
+ {
117
+ "ok": true,
118
+ "data": {
119
+ "dry_run": true,
120
+ "plan": {
121
+ "summary": "Would update 1 attr path(s) on module 'Hero CTA' (page #42, type divi/button).",
122
+ "changes": [
123
+ { "kind": "module.update", "target": "page#42/divi/button/Hero CTA#button.decoration.font.font.desktop.value.color", "before": "#000", "after": "#ff0066" }
124
+ ]
125
+ }
126
+ }
127
+ }
128
+ ```
306
129
 
307
- A handful of pre-existing tools predate the standard plan shape and keep their original response shapes for now: `preset_cleanup`, `preset_reassign`, `preset_delete`, `canvas_duplicate`, `page_trash`, `page_update_status`, `scf_sync`, `variable_create_fluid_system`.
130
+ `meta_wp_cli` and `scf_import` do not accept `dry_run` (raw passthrough / upstream gap respectively). For bulk preview-then-commit flows (preset reassign, preset cleanup), see [safety-patterns.md](../docs/safety-patterns.md).
308
131
 
309
- `meta_wp_cli` and `scf_import` do not accept `dry_run` — `meta_wp_cli` is a raw passthrough (use explicit read-only commands instead) and SCF's upstream `wp scf json import` lacks a `--dry-run` flag (use `scf_sync --dry_run` for the SCF-on-disk preview path).
132
+ ### `_meta.idempotent` markers
310
133
 
311
- ### Picking a pattern for a new tool
134
+ Every tool's `_meta.idempotent` field documents how it behaves under repeat calls with identical inputs. Some tools are silent-success idempotent (e.g. `page_trash` on an already-trashed post returns `ok: true` with `data.already_trashed = true`); others are side-effect-equivalent (re-running produces the same final state via different intermediate effects). See [idempotency-audit.md](../docs/idempotency-audit.md) for the per-tool record.
312
135
 
313
- Ask: **single item or many?** If single, Pattern A. If many, Pattern B (with `mode: "dry-run"/"apply"`). Either way, the universal `dry_run: boolean` knob is also available on every write tool — adding it on a new write tool is the default expectation.
136
+ ## Configuration
314
137
 
315
- Don't introduce a third pattern (`confirmation_token`, session-based preview, etc.) unless a tool has a genuine need that neither A nor B covers — both patterns above are stateless and flexible enough for most cases.
138
+ ### Environment variables
316
139
 
317
- ## Example Usage
140
+ | Variable | Required | Description |
141
+ |----------|----------|-------------|
142
+ | `WP_URL` | Yes | WordPress site URL (e.g. `http://mysite.local`) |
143
+ | `WP_USER` | Yes | WordPress username with Editor or Admin role |
144
+ | `WP_APP_PASSWORD` | Yes | Application Password (spaces stripped) |
145
+ | `WP_PATH` | No | WordPress filesystem path for Local by Flywheel, or wrapper working directory when `WP_CLI_CMD` needs project context |
146
+ | `WP_CLI_CMD` | No | Custom WP-CLI command prefix for containerized environments (e.g. `ddev wp`, `npx wp-env run cli wp`) |
147
+ | `LOCAL_SITE_ID` | No | Override auto-detection of Local by Flywheel site ID |
148
+ | `DIVIOPS_WP_CLI_ALLOW` | No | Opt-in extended WP-CLI commands — see [wp-cli-security.md](../docs/wp-cli-security.md) |
149
+ | `DIVIOPS_WP_CLI_SAFE_FS_ROOT` | No | Path to constrain filesystem-touching wp-cli commands. **Required** in `WP_CLI_CMD` wrapper mode |
150
+ | `DIVIOPS_WP_CLI_UNSAFE_FS` | No | Set to `1` to disable filesystem flag validation entirely |
318
151
 
319
- After setup, Claude can:
152
+ ### Containerized environments
320
153
 
321
- - "List all my Divi pages"
322
- - "Show me the layout structure of page 42"
323
- - "Create a new landing page with a hero section, 3-column features, and a CTA"
324
- - "Save the hero section from page 312 to the Divi Library"
325
- - "Validate this block markup before saving"
154
+ The server connects via standard WordPress REST API and works with any environment that exposes WordPress over HTTP with Application Password support — Local by Flywheel, DDEV, wp-env, WordPress Studio, DevKinsta, custom hosts. See [setup-guide.md](../docs/setup-guide.md) for environment-specific `WP_CLI_CMD` examples and HTTPS / `WP_ENVIRONMENT_TYPE` notes.
326
155
 
327
156
  ## Troubleshooting
328
157
 
329
- ### "Missing required environment variable(s)"
330
- Ensure `WP_URL`, `WP_USER`, and `WP_APP_PASSWORD` are all set. Check your `claude mcp add` command.
331
-
332
- ### "Connection failed" error
333
- - Verify the WP plugin is active: visit `{WP_URL}/wp-json/diviops/v1/schema/settings` in your browser
334
- - Check Application Password is correct (try with curl first)
158
+ Common quick fixes full reference in [troubleshooting.md](../docs/troubleshooting.md).
335
159
 
336
- ### "This tool requires plugin capability" error
337
- A specific tool failed at the per-tool capability gate (#486) because the active diviops-agent plugin doesn't advertise that capability. Update the plugin to ≥ 1.2.0 (the version that introduced the capability map). Other tools the older plugin does support keep working — the gate is per-tool, not a global floor.
160
+ - **"Missing required environment variable(s)"** — ensure `WP_URL`, `WP_USER`, `WP_APP_PASSWORD` are all set on `claude mcp add`.
161
+ - **"Connection failed"** verify the plugin is active by visiting `{WP_URL}/wp-json/diviops/v1/schema/settings`; test the credentials with `curl -u "user:pass" …`.
162
+ - **"This tool requires plugin capability"** — the plugin doesn't advertise the capability this tool needs. Update the plugin to the latest release.
163
+ - **Preset edits not visible on the frontend** — Divi serves frontend CSS from `wp-content/et-cache/{post_id}/`, which `wp cache flush` doesn't touch. Use `diviops_meta_flush_cache` after preset writes.
338
164
 
339
- ### "Server too old for plugin" error
340
- The plugin returned HTTP 426 because this MCP server is below the plugin's `MIN_SERVER_VERSION`. Update the MCP server (`npm install -g @diviops/mcp-server@latest` or rebuild from source).
165
+ ## Learn more
341
166
 
342
- ### "Permission denied" errors
343
- - The WP user must have `edit_posts` capability (Editor or Admin role)
344
- - Write operations (presets, library, theme builder) require `manage_options` (Admin role)
167
+ - [setup-guide.md](../docs/setup-guide.md) full onboarding walkthrough (containerized envs, HTTPS, Application Passwords)
168
+ - [server-reference.md](../docs/server-reference.md) full per-tool reference table
169
+ - [wp-cli-security.md](../docs/wp-cli-security.md) allowlist, extended commands, FS validation
170
+ - [safety-patterns.md](../docs/safety-patterns.md) — Pattern A (refuse-with-override) + Pattern B (preview-then-commit) + universal `dry_run`
171
+ - [troubleshooting.md](../docs/troubleshooting.md) — common errors and resolutions
172
+ - [idempotency-audit.md](../docs/idempotency-audit.md) — repeat-call semantics per tool
173
+ - **`divi-5-builder` Claude skill** — block format rules, design patterns, workflow guidance (ships in the dist repo)
345
174
 
346
- ### Testing manually
347
- ```bash
348
- curl -u "username:apppassword" http://site.local/wp-json/diviops/v1/schema/settings
349
- ```
350
-
351
- ### Preset edits not visible on the frontend
352
-
353
- After `preset_update` / `preset_create`, the preset option is updated immediately but Divi serves frontend CSS from a **per-post static cache** that neither `wp cache flush` nor `wp transient delete --all` invalidates.
354
-
355
- Cache location: `wp-content/et-cache/{post_id}/` — contains files like `et-divi-dynamic-tb-*-{post_id}-critical.css` with preset CSS baked in.
356
-
357
- To force regeneration for a specific page:
358
- ```bash
359
- rm -rf wp-content/et-cache/{post_id}/
360
- ```
361
-
362
- Next visit re-renders and writes fresh CSS. Applies to: any change that affects preset-derived CSS output (preset_update, preset_create when used by an existing page, preset_reassign in apply mode).
175
+ ## Requirements
363
176
 
364
- The preset option (`et_divi_builder_global_presets_d5`) always reflects the current MCP-written state if `wp option get et_divi_builder_global_presets_d5` shows your change but the frontend doesn't, it's this cache.
177
+ - Node.js >= 18.0.0
178
+ - PHP >= 7.4
179
+ - WordPress >= 6.5
180
+ - Divi 5 theme active
181
+ - DiviOps Agent WordPress plugin installed and active
365
182
 
366
183
  ## License
367
184
 
package/dist/index.js CHANGED
@@ -1708,7 +1708,7 @@ registerPluginTool("diviops_canvas_delete", {
1708
1708
  });
1709
1709
  // ── WP-CLI ──────────────────────────────────────────────────────────
1710
1710
  server.registerTool("diviops_meta_wp_cli", {
1711
- description: "Run a WP-CLI command on the WordPress site. Requires WP_PATH env var (LOCAL_SITE_ID auto-detected from Local by Flywheel), or WP_CLI_CMD for containerized wrappers. Commands validated against a safety allowlist. Default tier covers read ops across options/posts/post-types/taxonomies/users/info/core/db, non-destructive writes (post/term create+update, post meta read/write, cache/rewrite/transient flush), ACF/SCF schema ops (`acf export/import/field-group list/get` plus SCF 6.8.4+ `scf json {status,sync,import,export}` and the `acf json …` aliases), and WXR export. Extended tier (requires DIVIOPS_WP_CLI_ALLOW env var) adds destructive or bulk-modifying ops: option update, post/post meta/term delete, search-replace, import, plugin activate/deactivate, eval-file. Filesystem-touching commands (`wp export`, `acf export/import`, `scf|acf json export/import`) are additionally constrained: path arguments must resolve under a safe root (defaults to `<WP_PATH>/.diviops-tmp/`, overridable via DIVIOPS_WP_CLI_SAFE_FS_ROOT, disable via DIVIOPS_WP_CLI_UNSAFE_FS=1); `wp export` and `scf json export` require an explicit `--dir=<path>` (or `--stdout`). In WP_CLI_CMD wrapper mode, DIVIOPS_WP_CLI_SAFE_FS_ROOT is required for FS-sensitive commands. Prefer the typed `diviops_scf_*` wrappers for SCF round-trips — they're easier to invoke and accept the same safe-root scoping. Use --format=json for structured output. Full allowlist + tier rationale + filesystem semantics in the MCP server README. Returns the standardized envelope { ok, data?, error: { code, message, hint? } }. Success payload: { stdout: string, stderr: string, exit_code: 0 }. Four failure modes converge on 'meta_wp_cli.command_failed' with error.data = { exit_code: number | null, stdout: string, stderr: string }: (a) numeric exit_code — wp-cli ran and exited non-zero; stdout/stderr are raw streams verbatim. (b) exit_code=null and message starts with 'wp-cli command terminated:' — execFile launched the child but it was killed (timeout or signal); stdout/stderr carry whatever streamed before the kill. (c) exit_code=null and message starts with 'wp-cli could not spawn:' — the OS refused to start the child (ENOENT/EACCES/EPERM); child never ran, stdout/stderr are empty. (d) exit_code=null and message is the rejection reason — pre-execution rejection by the allowlist / FS validator; rejection reason synthesized into error.data.stderr because the child never ran. A missing wp-cli configuration surfaces as 'meta_wp_cli.not_configured'. stdout is always passed through as a string (no server-side JSON parse) — pass --format=json and parse on the caller side when you want structured output.",
1711
+ description: "Run a WP-CLI command on the WordPress site. Requires WP_PATH env var (LOCAL_SITE_ID auto-detected from Local by Flywheel), or WP_CLI_CMD for containerized wrappers. Commands validated against a safety allowlist. Default tier covers read ops across options/posts/post-types/taxonomies/users/info/core/db, non-destructive writes (post/term create+update, post meta read/write, cache/rewrite/transient flush, `plugin update` from authenticated sources), ACF/SCF schema ops (`acf export/import/field-group list/get` plus SCF 6.8.4+ `scf json {status,sync,import,export}` and the `acf json …` aliases), and WXR export. Extended tier (requires DIVIOPS_WP_CLI_ALLOW env var) adds destructive or bulk-modifying ops: option update, post/post meta/term delete, search-replace, import, plugin activate/deactivate, eval-file. Filesystem-touching commands (`wp export`, `acf export/import`, `scf|acf json export/import`) are additionally constrained: path arguments must resolve under a safe root (defaults to `<WP_PATH>/.diviops-tmp/`, overridable via DIVIOPS_WP_CLI_SAFE_FS_ROOT, disable via DIVIOPS_WP_CLI_UNSAFE_FS=1); `wp export` and `scf json export` require an explicit `--dir=<path>` (or `--stdout`). In WP_CLI_CMD wrapper mode, DIVIOPS_WP_CLI_SAFE_FS_ROOT is required for FS-sensitive commands. Prefer the typed `diviops_scf_*` wrappers for SCF round-trips — they're easier to invoke and accept the same safe-root scoping. Use --format=json for structured output. Full allowlist + tier rationale + filesystem semantics in the MCP server README. Returns the standardized envelope { ok, data?, error: { code, message, hint? } }. Success payload: { stdout: string, stderr: string, exit_code: 0 }. Four failure modes converge on 'meta_wp_cli.command_failed' with error.data = { exit_code: number | null, stdout: string, stderr: string }: (a) numeric exit_code — wp-cli ran and exited non-zero; stdout/stderr are raw streams verbatim. (b) exit_code=null and message starts with 'wp-cli command terminated:' — execFile launched the child but it was killed (timeout or signal); stdout/stderr carry whatever streamed before the kill. (c) exit_code=null and message starts with 'wp-cli could not spawn:' — the OS refused to start the child (ENOENT/EACCES/EPERM); child never ran, stdout/stderr are empty. (d) exit_code=null and message is the rejection reason — pre-execution rejection by the allowlist / FS validator; rejection reason synthesized into error.data.stderr because the child never ran. A missing wp-cli configuration surfaces as 'meta_wp_cli.not_configured'. stdout is always passed through as a string (no server-side JSON parse) — pass --format=json and parse on the caller side when you want structured output.",
1712
1712
  inputSchema: {
1713
1713
  command: z
1714
1714
  .string()
package/dist/wp-cli.js CHANGED
@@ -62,9 +62,14 @@ const DEFAULT_COMMANDS = [
62
62
  'rewrite flush',
63
63
  // Export (reads data, writes to file only)
64
64
  'export',
65
- // Info (read-only)
65
+ // Info (read-only + non-destructive writes)
66
66
  'cron event list',
67
67
  'plugin list',
68
+ // `plugin update` runs from authenticated sources (WP plugin repo or licensed
69
+ // update server) — same trust model as `core check-update`. Unlike `plugin
70
+ // activate` / `plugin deactivate` (extended tier), it does not enable
71
+ // previously-disabled code paths; it refreshes already-installed plugins.
72
+ 'plugin update',
68
73
  'theme list',
69
74
  'menu list',
70
75
  'site url',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@diviops/mcp-server",
3
- "version": "1.4.1",
3
+ "version": "1.5.2",
4
4
  "description": "MCP server exposing Divi 5 Visual Builder as tools for Claude",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",