elementor-live
Drives a live Elementor editor tab through Elementor's command API, allowing agents to inspect the canvas skeleton, inspect elements and widget controls, create/update/move/delete/duplicate elements in grouped undo steps, set custom CSS, save documents, capture screenshots, run design lint checks, and interact with the editor via an injected overlay and Alt+Space prompts.
Integrates with a WordPress site to open Elementor editor URLs or post IDs and, when REST credentials are configured, provides optional WordPress REST API access for managing posts, media, and options. It can create draft pages and open them in the editor, while refusing writes that contain _elementor_data so the open document is changed only through Elementor.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@elementor-live bump the hero heading to 64px, center it, and save as draft"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
elementor-live
An MCP server that lets coding agents (Claude Code, Kimi Code, Cursor, any MCP client) work on a live Elementor editor tab like an IDE. The agent sees what you select, changes the canvas through Elementor's own command API ($e.run) inside your Chrome tab — so every change is one undo step, Ctrl+Z works, and nothing fights over the database — moves a ghost cursor so you can follow along, takes pixel-accurate screenshots of what it built, and receives prompts you type directly in the editor with Alt+Space.
The loop:
open_editor → get_canvas_skeleton → inspect_element → mutate_canvas → capture_vision → (design_lint) → save_document
↑ │
└──────────── wait_for_user_prompt (Alt+Space in the editor) ──────┘There is no WordPress plugin. The server drives a dedicated Chrome window over the Chrome DevTools Protocol (Playwright) and injects a small overlay (cursor, speech bubble, HUD, prompt box) into the editor page.
Requirements
Node.js ≥ 20
Google Chrome installed (the system Chrome is used; no browser download)
A WordPress site with Elementor ≥ 3.x and a user who can edit pages. Tested on Elementor 4.3.5 with the Atomic editor enabled.
Related MCP server: visual-browser-agent
Install
git clone https://github.com/ArchiDoxx/elementor-live.git
cd elementor-live
npm install
npm run build
npx elementor-live doctordoctor prints the configuration, checks that Chrome is found and the profile directory is writable, and whether ELIVE_WP_URL responds (and authenticates, if REST credentials are set).
First run
ELIVE_WP_URL=https://your-site.example npx elementor-live openA Chrome window with its own profile (~/.elementor-live/profile) opens. Log in to WordPress once — the login persists in that profile — and open a page with "Edit with Elementor". You can also pass a post ID or an editor URL: npx elementor-live open 42.
Close it with Ctrl+C before you start your MCP client: the profile can only be used by one Chrome process at a time. The MCP server launches the same profile on the first tool call. To keep using a Chrome you started yourself, start it with --remote-debugging-port=9222 and set ELIVE_CDP_URL=http://localhost:9222.
MCP client configuration
Use the absolute path to dist/cli.js of your checkout. More snippets: docs/mcp-clients.md.
Claude Code
claude mcp add elementor-live -e ELIVE_WP_URL=https://your-site.example -- node /abs/path/elementor-live/dist/cli.jsKimi Code, Cursor and other JSON-configured clients (mcpServers):
{
"mcpServers": {
"elementor-live": {
"command": "node",
"args": ["/abs/path/elementor-live/dist/cli.js"],
"env": {
"ELIVE_WP_URL": "https://your-site.example"
}
}
}
}The server speaks MCP over stdio; it logs only to stderr.
Tools
Tool | Input | Output |
| – | connected, editorUrl, postId, title, documentType, elementorVersion, atomicEnabled, selection, lastSeq |
|
| same as |
|
| compressed tree |
|
| non-default settings, controlsHint, box, computed styles, text, scrollOverflowX, parentChain, children |
|
|
|
|
| control definitions (type, default, options capped at 30) |
|
| per-op results |
|
| ok, status |
|
| PNG image + |
|
| findings |
|
| ok |
|
| ok |
|
| events since seq, lastSeq |
|
|
|
|
| JSON (only when REST credentials are configured) |
mutate_canvas operations:
{ "op": "create", "parentId": "c1a2b3", "at": 0, "elType": "widget", "widgetType": "heading", "settings": { "title": "Hello" } }
{ "op": "update_settings", "id": "h4d5e6", "settings": { "title_color": "#1a1a1a" } }
{ "op": "move", "id": "h4d5e6", "parentId": "c7f8g9", "at": 1 }
{ "op": "delete", "id": "b1c2d3" }
{ "op": "duplicate", "id": "c1a2b3" }
{ "op": "set_custom_css", "id": "c1a2b3", "css": "selector { scroll-margin-top: 80px; }" }All ops of one call form a single undo step. Element IDs come only from get_canvas_skeleton or from create/duplicate results; within one batch, "$0", "$1", … as id/parentId refer to the element created by that op index, so a container and its children fit into one undo step. A failing op does not stop the others.
Errors are returned as tool results with isError: true and a JSON body { "error", "code", "hint" }, e.g. not_connected, no_editor_tab, element_not_found, invalid_ops.
The server also provides the prompt elementor_workflow (a short guide for the agent) and the resource elementor-live://status.
Tag-team with Alt+Space
Ask your agent to "work with me in the editor" — it calls
wait_for_user_prompt.In the Elementor editor, select an element and press Alt+Space. Type what you want ("make this a two-column layout with an image on the right") and press Enter.
The agent receives your text plus the current selection, makes the change (one undo step), shows a speech bubble at the element, and waits for the next prompt.
Edits you make yourself show up in get_user_activity, so the agent can re-read an element before touching it again.
Example prompts
"Open page 42 in Elementor and describe its structure."
"Build a hero section at the top: full-width container, heading, short text, two buttons side by side. Then show me a screenshot."
"The selected section looks cramped on mobile — check it with design_lint and capture_vision on mobile, then propose fixes."
"Rename every 'Learn more' button on this page to 'Read the case study'."
"Create a draft page 'Pricing' via wp_rest and open it in the editor."
Environment variables
Variable | Default | Meaning |
| – | Base URL of the WordPress site; needed for |
|
| Chrome profile directory (keeps the WordPress login) |
| – | Attach to a running Chrome (e.g. |
|
|
|
| – | WordPress user for |
| – | Application Password for |
wp_rest is registered only when ELIVE_WP_URL, ELIVE_WP_USER and ELIVE_WP_APP_PASSWORD are all set. It is meant for posts, media and options; it refuses writes containing _elementor_data, because the open document must only be changed through the editor.
Development
bash dev/bootstrap.sh # WSL/Linux with Docker: WordPress + MariaDB + wp-cli on http://localhost:8080, Elementor and a test page
npm test # unit tests (vitest)
npm run typecheck
npm run e2e # Playwright flows against the dev instance (real $e.run, undo, save, screenshot)
npx tsx e2e/mcp-smoke.ts # acceptance run: built server over stdio, driven by a real MCP client
npm run dev # run the CLI from source via tsxThe dev instance's admin login defaults to admin / admin (ELIVE_DEV_USER, ELIVE_DEV_PASS, ELIVE_DEV_URL override it).
Limitations
Elementor V4 atomic elements (
e-flexbox,e-heading, …) are shown in the skeleton and can be created, but their style props cannot be edited via settings yet (unsupported_atomic). Prefer classic widgets insidecontainerelements.set_custom_csswritescustom_css, which needs Elementor Pro.One editor tab and one document at a time; theme-builder documents are not targeted.
No voice input.
Long
wait_for_user_promptcalls depend on your client's request timeout; use a smallertimeoutSecif your client aborts early.
Architecture
See the design spec: docs/superpowers/specs/2026-10-26-elementor-live-design.md (German). In short: src/server.ts and src/tools/* (MCP layer), src/browser/* (Playwright session, $e.run snippets, overlay), src/core/* (pure skeleton/ops/lint logic), src/wp/rest.ts (optional REST client).
License
MIT — see LICENSE.
Available Tools
14 toolsagent_saySpeak in the editorA
Show a short speech bubble from the agent inside the user's editor, anchored at an element (id, the ghost cursor moves there) or at the top of the canvas. Use it to explain what you are about to change, to point at lint findings, or to ask the user something while they watch the canvas. Keep messages under ~200 characters. mood tints the bubble: neutral, happy, thinking, warning, sassy.
Inputs: message (required), id, mood.
canvas_statusEditor statusARead-only
Report the state of the live Elementor editor tab: whether a session is connected, the editor URL, postId, document title and type, Elementor version, whether V4 atomic elements are enabled, the current user selection (element IDs) and lastSeq of the activity buffer. Call this first in every session; if connected is false or the call fails with not_connected/no_editor_tab, call open_editor. The first call may start the dedicated Chrome window.
Inputs: no named parameters.
capture_visionCapture screenshotARead-only
Take a pixel-accurate PNG screenshot of one element (id) or of the whole preview viewport (no id), as rendered in the live editor; the ghost cursor moves to the element first so the user sees what you look at. device switches the editor's responsive mode (desktop, tablet, mobile) before capturing. Use it after every meaningful mutation to verify the visual result instead of assuming it. Returns the image plus {box, bytes}.
Inputs: id, device.
design_lintDesign lintARead-only
Check rendered geometry for common layout problems: spacing off the grid (grid, default 4 px), children overflowing their parent, overlapping siblings, headings that wrap, horizontal scroll, tap targets smaller than 44 px, empty containers. With id only that element and its descendants are reported. Findings are suggestions: show them to the user (agent_say with id) and only fix what the user wants — do not silently override deliberate design choices.
Inputs: id, grid.
get_canvas_skeletonCanvas skeletonARead-only
Return the compressed element tree of the open document: {id, elType, widgetType, label, atomic?, children} per node, plus the current user selection, nodeCount, recent user events (selections, edits, Alt+Space prompts, saves) and lastSeq. This is the only source of element IDs besides create results — never invent IDs. Pass since= to receive only newer events; without it the last 20 events are returned. includeSettings=true adds non-default settings per node (more tokens); use inspect_element for a single element instead. maxDepth limits nesting for very large pages.
Inputs: since, maxDepth, includeSettings.
get_user_activityUser activityARead-only
Return what the user did in the editor since a sequence number: selections (ids), edits (change events with the history title and ids), Alt+Space prompts (text), saves and navigations, plus lastSeq. Pass since= to get only new events; re-read get_canvas_skeleton or inspect_element for elements the user changed before mutating them, so you do not overwrite their edits.
Inputs: since.
get_widget_controlsWidget controlsARead-only
Return the control definitions (setting keys) of a widget type or elType, e.g. "heading", "button" or "container": name, type, label, default, options (capped at 30), section, tab, responsive. Call this before writing settings you have not seen in inspect_element — never guess setting keys. Responsive controls accept suffixed keys (name_tablet, name_mobile). Value shapes follow the control type: dimensions {unit, top, right, bottom, left, isLinked}, sliders {unit, size}, colors as hex strings, selects as one of the option keys.
Inputs: widgetType (required).
inspect_elementInspect elementARead-only
Inspect one element by ID (from get_canvas_skeleton or a create result): non-default settings, controlsHint (the most relevant setting keys for this widget type), rendered bounding box in the preview iframe, an excerpt of computed styles (display, padding, margins, gap, font size, line height, overflow), visible text, whether it overflows horizontally, its parent chain and direct children. Use it before update_settings to see the current values and their exact shapes; call get_widget_controls when you need a key that is not in controlsHint. Fails with element_not_found for unknown IDs.
Inputs: id (required).
list_widgetsList widgetsARead-only
List the widget types registered in this Elementor installation as [{type, title, categories, atomic}]. Use filter (case-insensitive substring of type or title) to search, e.g. "button" or "image". Use the type as widgetType in a create op with elType "widget". Prefer classic widgets (heading, text-editor, button, image, icon-list …) inside "container" elements; atomic types (prefixed "e-") are Elementor V4 elements and may reject classic settings.
Inputs: filter.
mutate_canvasMutate canvasADestructive
Apply a batch of operations to the open document through Elementor's own command API, in the user's editor tab, as ONE undo step titled after label (the user can press Ctrl+Z). Ops: create {parentId?, at?, elType, widgetType?, settings?} (omit parentId to append at document root; elType "widget" needs widgetType), update_settings {id, settings} (merges keys), move {id, parentId, at?}, delete {id}, duplicate {id}, set_custom_css {id, css} (Elementor Pro custom_css; "selector" refers to the element). IDs must come from get_canvas_skeleton or from earlier create/duplicate results (returned per op as id) — never invent them. Within one batch, "$N" (e.g. "$0") as id/parentId refers to the element created by op N of the same batch, so a container and its children can be built in one undo step. Prefer elType "container" with flex settings (flex_direction, flex_gap, flex_justify_content, flex_align_items) over legacy section/column. Check keys with get_widget_controls first. Atomic V4 elements (elType/widgetType "e-*") can be created, but may reject classic settings (code unsupported_atomic). A failing op does not stop the others; inspect results[] and verify visually with capture_vision.
Inputs: ops (required), label.
open_editorOpen Elementor editorAIdempotent
Navigate the dedicated Chrome tab to the Elementor editor of a page and wait until the editor ($e) is ready. Pass either postId (requires ELIVE_WP_URL; opens /wp-admin/post.php?post=&action=elementor) or a full editor url. Returns the same status object as canvas_status. If WordPress shows a login page, ask the user to log in once in that Chrome window and call open_editor again. After opening, call get_canvas_skeleton to learn element IDs.
Inputs: url, postId.
save_documentSave documentAIdempotent
Save the open document via Elementor's save commands. mode "draft" saves a draft/revision without publishing, "update" saves an already published page, "publish" publishes it. Only save when the user asked for it or confirmed the result; mutations are visible in the editor before saving.
Inputs: mode (required).
set_hudUpdate HUDAIdempotent
Update the small heads-up badge in the editor top bar: score (e.g. a 0–100 design quality estimate), delta (change since the last update, shown as +/-) and a short note. Purely informational for the user; it does not change the document.
Inputs: note, delta, score.
wait_for_user_promptWait for user promptARead-only
Block until the user presses Alt+Space in the Elementor editor and submits a prompt, then return {text, selection, seq} — selection holds the element IDs the user had selected, which is what "this" refers to in the prompt. Returns {timeout: true} after timeoutSec (default 120, max 600). Use it for tag-team work: finish a task, call agent_say to report, then wait for the next prompt in a loop. If your MCP client enforces a short request timeout, pass a smaller timeoutSec and call again.
Inputs: timeoutSec.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 14 tools
Most tools target clearly distinct resources or actions (skeleton vs. single-element inspect, mutate vs. save, widgets vs. controls). There is mild overlap in the user-event area: get_canvas_skeleton also returns recent events, get_user_activity is a dedicated event feed, and wait_for_user_prompt surfaces Alt+Space prompts, so an agent could pick the wrong one. canvas_status and open_editor also both return the same status object, though the descriptions sequence them clearly.
The dominant pattern is snake_case verb_noun (get_canvas_skeleton, list_widgets, inspect_element, save_document, capture_vision, open_editor, mutate_canvas). A few deviate to noun_verb or noun_state forms (canvas_status, design_lint, agent_say, set_hud), but names remain readable and largely predictable. Minor inconsistency, not confusing.
14 tools is well within the healthy range and each has a distinct role: session setup, discovery, mutation, verification, and user interaction. Nothing feels padded; even the UX tools (set_hud, agent_say) serve the live-editor collaboration model.
The surface covers the full edit lifecycle: connect, discover widgets/controls, read tree and element detail, batch create/update/move/delete/duplicate/custom CSS, save, screenshot-verify, and lint. Gaps exist: no media library/upload tool (images must already exist as attachment IDs), no document/page-level settings or global styles access, no history/undo tool (relies on the user pressing Ctrl+Z), and no template save/insert.
Maintenance
Related MCP Connectors
Let AI agents use your real, signed-in Chrome: tabs, clicks, forms, screenshots and video.
Control a real browser from AI agents: navigate, click, type, screenshot, read the page.
Lets your AI build and edit websites in Xodia, a visual website builder for real code (Vite, React, Tailwind CSS or plain HTML in your own git repo): read and write site files, create pages and CMS collections, run typecheck, design and link checks, take screenshots, manage forms and translations, and pick up change requests the user sends from the visual editor. Sign in once with your Xodia account (OAuth). Free plan, no card needed. Setup: https://xodia.ai/ai/mcp
Give agents eyes on any web page: structured context, and changes explained in plain language.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables AI coding agents to visually interact with frontend apps by taking screenshots, clicking elements, reading console logs, and performing visual diffs.7 npm3MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI coding agents to see and interact with real Chrome pages through structured DOM inspection, targeted screenshots, recordings, and human-in-the-loop approvals across major coding-agent hosts.MIT
- AlicenseNot gradedqualityBmaintenanceEnables coding agents to capture pixel-accurate screenshots and DOM state from localhost apps, receive user-drawn instructions and reference images, and manage implementation review cycles.21 npmMIT
- AlicenseNot gradedqualityBmaintenanceEnables coding agents to control the user's real Chrome or Firefox tabs, with their existing logins, to read pages, click, type, fill forms, take screenshots, inspect network traffic and run JavaScript. It works through a paired browser extension over a local WebSocket connection, so automation happens in the browser the user is actually looking at, including shadow DOM, cross-origin iframes, dialogs and single-page apps.MIT