elementor-mcp-agent 0.1.0 → 1.0.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,114 @@ 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
72
+ ---
107
73
 
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
- ```
74
+ ## Tools (24)
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
+ ### Fleet
108
+ - `check_elementor_versions` — flag outdated installs against wordpress.org latest
113
109
 
114
110
  ---
115
111
 
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. |
112
+ ## Safety guarantees
129
113
 
130
- ## Resources
114
+ Hardcoded in `src/elementor/policies.ts`:
131
115
 
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:
116
+ ```ts
117
+ BACKUP_BEFORE_WRITE = true
118
+ BACKUP_PAGE_SETTINGS = true
119
+ VALIDATE_JSON_AFTER_EDIT = true
120
+ BLOCK_GLOBAL_WIDGET_WRITES_BY_DEFAULT = true
121
+ CONFIRMATION_TTL_SECONDS = 60
122
+ GLOBAL_WIDGET_CONFIRMATION_TTL_SECONDS = 30
123
+ FLUSH_CSS_AFTER_WRITE = true
124
+ MAX_ELEMENTOR_DATA_BYTES = 5_000_000
125
+ ```
133
126
 
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
127
+ And these wp-cli patterns are **hard-blocked** regardless of confirmation:
128
+ - `rm -rf`
129
+ - `sudo *`
130
+ - `db reset --yes` / `db drop --yes`
137
131
 
138
132
  ---
139
133
 
140
- ## Safety patterns
141
-
142
- Every destructive operation follows the same dance:
134
+ ## End-to-end verified
143
135
 
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).
136
+ v1.0.0 was tested in real conditions against a live WordPress install with Elementor 4.0.9:
147
137
 
148
- The backup is **never deleted** — purge old `_elementor_data_backup_*` postmeta keys yourself when no longer needed.
138
+ - 21/24 tools validated end-to-end
139
+ - ✅ find_replace → backup → restore round-trip preserves data
140
+ - ✅ duplicate_page copies data + page_settings + edit_mode
141
+ - ✅ apply_template_to_page with auto-backup
142
+ - ✅ wp_cli_run destructive flow (post delete) requires confirmation
143
+ - ✅ screenshots identical detection via SHA-256
144
+ - ✅ CSS flush uses `wp elementor flush-css` when SSH available, falls back to option-delete otherwise
149
145
 
150
- ---
151
-
152
- ## Rate limiting
153
-
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.
146
+ 7 bugs found during testing, all fixed:
147
+ - REST API silently drops unregistered postmeta writes → switched to WP-CLI primary for backups
148
+ - `wp` not in SSH PATH on managed hosts → auto-detection + `wp_cli_path` config
149
+ - SSH post-quantum banner pollution → stderr filter
150
+ - Default Kit returned as "widget" client-side filter
151
+ - `_elementor_page_settings` type object/string mismatch → normalisation
152
+ - Chrome cold-start screenshot timeout → bumped to 60s
153
+ - Templates listing same filter bug → fixed
155
154
 
156
155
  ---
157
156
 
158
157
  ## Roadmap
159
158
 
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
165
-
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)
171
-
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
176
-
177
- ---
178
-
179
- ## Architecture
159
+ **v1.1**
160
+ - Widget-level CRUD: `read_widget`, `update_widget_settings`, `add_widget`, `delete_widget`, `swap_widget_type`
161
+ - `bulk_find_replace_site` (across all Elementor pages of one site)
162
+ - `restore_from_file` tool
180
163
 
181
- See [ARCHITECTURE.md](./ARCHITECTURE.md) for the full design rationale.
164
+ **v1.2**
165
+ - `fleet_find_replace` (across all sites in pool)
166
+ - Global styles read/write
167
+ - Theme Builder template push across sites
182
168
 
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.
169
+ **v2.0**
170
+ - WooCommerce-aware tools
171
+ - Visual diff (pixel comparison)
172
+ - Schedule + cron scheduling
184
173
 
185
174
  ---
186
175