elementor-mcp-agent 0.1.0 → 1.1.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/README.md CHANGED
@@ -3,29 +3,23 @@
3
3
  [![npm version](https://img.shields.io/npm/v/elementor-mcp-agent.svg)](https://www.npmjs.com/package/elementor-mcp-agent)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
5
5
 
6
- > **Agency-grade MCP server for WordPress Elementor.** Multi-site management, safe Elementor data editing with backup + dry-run + CSS-flush, template export/import across sites, version tracking, and a curated Elementor docs corpus exposed as MCP resources.
6
+ > **Agency-grade MCP server for WordPress Elementor.** Multi-site management, safe Elementor edits with backup + auto-rollback + CSS flush, template export/import, global widget detection, screenshots, WP-CLI escape hatch.
7
7
 
8
- Built for agencies running many client sites on Elementor / Elementor Pro who want Claude (or any MCP client) to drive the toil — without breaking pages.
8
+ Built for agencies running many client sites on Elementor / Elementor Pro who want Claude (or any MCP client) to drive the toil — **without breaking pages**.
9
9
 
10
10
  ---
11
11
 
12
12
  ## Why this exists
13
13
 
14
- There are ~25 WordPress MCP servers on GitHub today. None target the **agency** use case:
14
+ There are 25+ WordPress MCP servers on GitHub today. None targets the **agency multi-site workflow** with:
15
15
 
16
- - **Multi-site** list, ping, and act on a pool of sites in one prompt.
17
- - **Elementor-aware** understands `_elementor_data` structure, not just generic WP REST.
18
- - **Defensive editing** auto-backup before any change, dry-run + confirmation token for destructive ops, CSS regeneration on save.
19
- - **Cross-site template sync** export from staging, import on every client site in one shot.
20
- - **Version oversight** — see who's running which Elementor / Elementor Pro version across the whole fleet.
21
-
22
- This MCP starts with these four pillars and grows from there.
23
-
24
- ---
25
-
26
- ## ⚠️ Status: early days
27
-
28
- v0.1.0 is shipped end-to-end (CI green, 14 tests passing, npm + MCP Registry listed) but the tool surface is intentionally focused. Expect rapid iteration. Don't run destructive operations on production without testing on staging first.
16
+ - **Real backup before every edit** (postmeta via WP-CLI when SSH available, JSON file fallback never silently lost)
17
+ - **Two-call confirmation** for any destructive op (TTL 60s)
18
+ - **JSON validation + auto-rollback** if an edit produces invalid Elementor data
19
+ - **3-level CSS flush fallback** (REST wp-cli native option/meta delete re-save)
20
+ - **Global widget awareness** — preflight check warns if a page references shared widgets
21
+ - **WP-CLI escape hatch** for everything the REST API can't do safely
22
+ - **Screenshots** via headless Chrome (no puppeteer dep)
29
23
 
30
24
  ---
31
25
 
@@ -35,59 +29,31 @@ v0.1.0 is shipped end-to-end (CI green, 14 tests passing, npm + MCP Registry lis
35
29
  npx -y elementor-mcp-agent
36
30
  ```
37
31
 
38
- Or globally:
39
-
40
- ```bash
41
- npm install -g elementor-mcp-agent
42
- ```
43
-
44
32
  ## Configure
45
33
 
46
- The server needs to know about your sites. The simplest path: an env var with a JSON array.
47
-
48
34
  ```bash
49
- export ELEMENTOR_MCP_SITES='[
50
- {
51
- "id": "client-acme",
52
- "url": "https://acme.example.com",
53
- "username": "admin",
54
- "application_password": "xxxx xxxx xxxx xxxx xxxx xxxx"
55
- },
56
- {
57
- "id": "client-beta",
58
- "url": "https://beta.example.com",
59
- "username": "admin",
60
- "application_password": "yyyy yyyy yyyy yyyy yyyy yyyy"
35
+ export ELEMENTOR_MCP_SITES='[{
36
+ "id": "client-acme",
37
+ "url": "https://acme.example.com",
38
+ "username": "admin",
39
+ "application_password": "xxxx xxxx xxxx xxxx xxxx xxxx",
40
+ "ssh": {
41
+ "host": "host.example.com",
42
+ "user": "username",
43
+ "port": 22,
44
+ "path": "/path/to/wordpress",
45
+ "wp_cli_path": "wp"
61
46
  }
62
- ]'
47
+ }]'
63
48
  ```
64
49
 
65
- Generate the **WordPress Application Password** at:
66
- `https://{your-site}/wp-admin/profile.php#application-passwords-section`
50
+ Generate the **WordPress Application Password** at `https://{your-site}/wp-admin/profile.php#application-passwords-section`.
67
51
 
68
- (`Application Passwords` is a built-in WordPress 5.6+ feature. No plugin required.)
52
+ The `ssh` block is **optional** but unlocks **8 additional tools** (WP-CLI escape hatch + reliable custom-postmeta backups). The MCP works without SSH — backups go to local JSON files instead.
69
53
 
70
- Or use a config file:
54
+ `wp_cli_path` auto-detects if omitted (tries `wp`, then `~/bin/wp.phar`, then `~/wp-cli.phar`).
71
55
 
72
- ```bash
73
- export ELEMENTOR_MCP_CONFIG_PATH="/path/to/sites.json"
74
- ```
75
-
76
- With `sites.json`:
77
- ```json
78
- {
79
- "sites": [
80
- { "id": "...", "url": "...", "username": "...", "application_password": "..." }
81
- ],
82
- "default_site_id": "client-acme",
83
- "rate_limit_per_minute": 60,
84
- "confirmation_ttl_seconds": 60
85
- }
86
- ```
87
-
88
- ### Configure Claude Desktop
89
-
90
- `~/Library/Application Support/Claude/claude_desktop_config.json`:
56
+ ### Claude Desktop config
91
57
 
92
58
  ```json
93
59
  {
@@ -96,91 +62,129 @@ With `sites.json`:
96
62
  "command": "npx",
97
63
  "args": ["-y", "elementor-mcp-agent"],
98
64
  "env": {
99
- "ELEMENTOR_MCP_SITES": "[{\"id\":\"acme\",\"url\":\"https://acme.com\",\"username\":\"admin\",\"application_password\":\"xxxx...\"}]"
65
+ "ELEMENTOR_MCP_SITES": "[{\"id\":\"acme\",\"url\":\"https://acme.com\",\"username\":\"admin\",\"application_password\":\"...\"}]"
100
66
  }
101
67
  }
102
68
  }
103
69
  }
104
70
  ```
105
71
 
106
- ### Configure Claude Code
107
-
108
- ```bash
109
- claude mcp add elementor \
110
- -e ELEMENTOR_MCP_SITES='[{"id":"acme","url":"https://acme.com","username":"admin","application_password":"xxxx..."}]' \
111
- -- npx -y elementor-mcp-agent
112
- ```
113
-
114
72
  ---
115
73
 
116
- ## Tools (v0.1)
117
-
118
- | Tool | What it does |
119
- |---|---|
120
- | `list_sites` | Lists every site in the pool (id, url, username, has_ssh). |
121
- | `ping_site` | Verifies auth + reports WP / Elementor / Elementor Pro versions. |
122
- | `list_elementor_pages` | Lists pages built with Elementor on a given site. |
123
- | `read_page_elementor` | Returns a structured summary of a page's `_elementor_data` (widget counts by type, depth). Full tree with `verbose=true`. |
124
- | `elementor_find_replace` | Find/replace plain text in every widget on a page. **Two-call destructive flow**: dry-run returns a count + token; second call with token applies after auto-backup. |
125
- | `list_elementor_templates` | Lists library templates (sections, pages, popups, headers, footers). |
126
- | `export_elementor_template` | Exports a template as portable JSON. |
127
- | `import_elementor_template` | Imports a portable JSON template into a target site. |
128
- | `check_elementor_versions` | Fleet-wide Elementor version audit. Flags outdated installs against wordpress.org latest. |
129
-
130
- ## Resources
131
-
132
- The server exposes a hand-curated set of Elementor reference docs as MCP `resources`, so the LLM can look up hook names, widget structure, and safe editing patterns without leaving its context:
133
-
134
- - `elementor-docs://hooks-actions.md` — common action hooks + filters
135
- - `elementor-docs://widget-structure.md` — `_elementor_data` schema + common widget types
136
- - `elementor-docs://safe-editing.md` — backup, dry-run, CSS flush patterns
74
+ ## Tools (34)
75
+
76
+ ### Sites & health
77
+ - `list_sites` — enumerate the pool
78
+ - `ping_site` auth + version probe
79
+ - `site_health` multi-call health snapshot
80
+
81
+ ### Pages
82
+ - `list_elementor_pages` pages in builder mode
83
+ - `read_page_elementor` parsed summary + optional full tree
84
+ - `list_widgets_in_page` flat widget inventory with excerpts
85
+ - `list_global_widgets` shared widgets (edit one affects every page using it)
86
+ - `preflight_check` validate a page is safe to edit
87
+ - `elementor_find_replace` — text replace with **dry-run → token → apply → backup → validate → rollback if invalid**
88
+ - `list_elementor_backups` / `restore_elementor_backup` — full restore chain with pre-restore safety backup
89
+ - `duplicate_elementor_page` — clone within a site (data + page_settings + edit_mode)
90
+
91
+ ### Templates
92
+ - `list_elementor_templates` — Theme Builder distinguished from regular library
93
+ - `export_elementor_template` — portable JSON
94
+ - `import_elementor_template` — drop into target site
95
+ - `apply_template_to_page` — push template data onto an existing page
96
+
97
+ ### WP-CLI escape hatch (require SSH)
98
+ - `wp_cli_run` — arbitrary wp-cli command with destructive-pattern detection + confirmation
99
+ - `wp_search_replace` — `wp search-replace` with mandatory dry-run
100
+ - `wp_elementor_flush_css` — 3-level fallback
101
+ - `wp_plugin_list` / `wp_plugin_update` (with confirmation)
102
+
103
+ ### Visual
104
+ - `screenshot_page` — headless Chrome PNG of any URL
105
+ - `compare_screenshots` — SHA-256 + byte-delta
106
+
107
+ ### Widgets (v1.1 — widget-level CRUD)
108
+ - `read_widget` — fetch one widget by id (read-only)
109
+ - `update_widget_settings` — shallow-merge settings, with backup + validate + flush
110
+ - `delete_widget` — remove a widget from its parent container
111
+ - `duplicate_widget` — clone as sibling with fresh id
112
+ - `swap_widget_type` — replace widgetType + settings, preserve id + position
113
+ - `add_widget` — append a widget into a parent container
114
+ - `move_widget` — move a widget between containers (with position)
115
+
116
+ ### Bulk & fleet (v1.1)
117
+ - `bulk_find_replace_site` — find/replace across every Elementor page of one site, per-page backup + validate + flush
118
+ - `fleet_find_replace` — same across **every site in the pool** (sequential, dry-run mandatory)
119
+ - `restore_from_file` — restore `_elementor_data` from a JSON file backup, with pre-restore safety backup
120
+
121
+ ### Fleet
122
+ - `check_elementor_versions` — flag outdated installs against wordpress.org latest
137
123
 
138
124
  ---
139
125
 
140
- ## Safety patterns
126
+ ## Safety guarantees
141
127
 
142
- Every destructive operation follows the same dance:
128
+ Hardcoded in `src/elementor/policies.ts`:
143
129
 
144
- 1. **First call** (no `confirmation` arg) → dry-run. Returns `match_count` + `confirmation_token` (TTL 60s, configurable).
145
- 2. **Second call** (same args + token) → applies after backing up the page's `_elementor_data` to a timestamped postmeta key.
146
- 3. **CSS flush** is triggered automatically (REST `/elementor/v1/css?action=regenerate`, falls back to re-save).
147
-
148
- The backup is **never deleted** — purge old `_elementor_data_backup_*` postmeta keys yourself when no longer needed.
149
-
150
- ---
151
-
152
- ## Rate limiting
130
+ ```ts
131
+ BACKUP_BEFORE_WRITE = true
132
+ BACKUP_PAGE_SETTINGS = true
133
+ VALIDATE_JSON_AFTER_EDIT = true
134
+ BLOCK_GLOBAL_WIDGET_WRITES_BY_DEFAULT = true
135
+ CONFIRMATION_TTL_SECONDS = 60
136
+ GLOBAL_WIDGET_CONFIRMATION_TTL_SECONDS = 30
137
+ FLUSH_CSS_AFTER_WRITE = true
138
+ MAX_ELEMENTOR_DATA_BYTES = 5_000_000
139
+ ```
153
140
 
154
- Per-site token bucket, default **60 req/min** (matches what most managed WordPress hosts allow on `wp-json`). Override via `rate_limit_per_minute` in config.
141
+ And these wp-cli patterns are **hard-blocked** regardless of confirmation:
142
+ - `rm -rf`
143
+ - `sudo *`
144
+ - `db reset --yes` / `db drop --yes`
155
145
 
156
146
  ---
157
147
 
158
- ## Roadmap
148
+ ## End-to-end verified
159
149
 
160
- **v0.2**
161
- - [ ] `widget_swap` — replace one widget by another with field mapping
162
- - [ ] `restore_elementor_backup` — restore a page from a timestamped backup
163
- - [ ] `bulk_find_replace` — apply find/replace across all pages of a site
164
- - [ ] WP-CLI runner via SSH for ops the REST API can't do
150
+ v1.0.0 was tested in real conditions against a live WordPress install with Elementor 4.0.9:
165
151
 
166
- **v0.3**
167
- - [ ] Cross-site template push (`push_template_to_all`)
168
- - [ ] Fleet health: outdated plugins, broken links, PageSpeed snapshot
169
- - [ ] Visual diff (screenshot before/after)
170
- - [ ] Elementor Pro version detection from Pro server (currently free-only)
152
+ - ✅ 21/24 tools validated end-to-end
153
+ - find_replace → backup → restore round-trip preserves data
154
+ - duplicate_page copies data + page_settings + edit_mode
155
+ - apply_template_to_page with auto-backup
156
+ - wp_cli_run destructive flow (post delete) requires confirmation
157
+ - ✅ screenshots identical detection via SHA-256
158
+ - ✅ CSS flush uses `wp elementor flush-css` when SSH available, falls back to option-delete otherwise
171
159
 
172
- **v1.0**
173
- - [ ] Mature widget mutation API (typed setters per widget type)
174
- - [ ] Automated docs ingestion from developer.elementor.com
175
- - [ ] Per-tool happy-path tests against a real Elementor install
160
+ 7 bugs found during testing, all fixed:
161
+ - REST API silently drops unregistered postmeta writes switched to WP-CLI primary for backups
162
+ - `wp` not in SSH PATH on managed hosts → auto-detection + `wp_cli_path` config
163
+ - SSH post-quantum banner pollution stderr filter
164
+ - Default Kit returned as "widget" → client-side filter
165
+ - `_elementor_page_settings` type object/string mismatch → normalisation
166
+ - Chrome cold-start screenshot timeout → bumped to 60s
167
+ - Templates listing same filter bug → fixed
176
168
 
177
169
  ---
178
170
 
179
- ## Architecture
180
-
181
- See [ARCHITECTURE.md](./ARCHITECTURE.md) for the full design rationale.
171
+ ## Roadmap
182
172
 
183
- Short version: stdio MCP, Zod-validated tools, token-bucket throttling, confirmation tokens for destructive ops, pino logs to stderr (never stdout), tsup bundle, vitest tests.
173
+ **v1.1** shipped
174
+ - Widget-level CRUD: `read_widget`, `update_widget_settings`, `delete_widget`, `duplicate_widget`, `swap_widget_type`, `add_widget`, `move_widget`
175
+ - `bulk_find_replace_site` (across all Elementor pages of one site)
176
+ - `fleet_find_replace` (across all sites in pool)
177
+ - `restore_from_file`
178
+
179
+ **v1.2**
180
+ - Global styles read/write
181
+ - Theme Builder template push across sites
182
+ - Section/column-level operations
183
+
184
+ **v2.0**
185
+ - WooCommerce-aware tools
186
+ - Visual diff (pixel comparison)
187
+ - Schedule + cron scheduling
184
188
 
185
189
  ---
186
190