Labsco
Mogacode-ma logo

elementor-mcp-agent

from Mogacode-ma

Agency-grade MCP server for WordPress Elementor β€” multi-site fleet management, safe page/widget-level editing, template export/import, version tracking with snapshot/rollback.

πŸ”₯πŸ”₯πŸ”₯βœ“ VerifiedFreeQuick setup

elementor-mcp-agent

Mogacode-ma/elementor-mcp-agent MCP server

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.

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.


How this was built

elementor-mcp-agent was built end-to-end with Claude Code over ~48 hours. The process is intentionally open:

  • Architecture, code, tests, docs β€” all generated through Claude Code pair-programming sessions
  • The 7 bugs documented in this post-mortem were caught in real E2E testing against a live WordPress + Elementor install, not after the fact
  • v1.2's post-write verification pattern was shipped 2 hours after a reader's comment (Mads Hansen on Dev.to) β€” the changelog credits the source

This isn't vibe-coded software thrown over the wall. Every release ran through lint + typecheck + 27 unit tests + (for v1.0) full E2E against a real WordPress install before publishing. The MCP itself hardcodes guardrails that prevent the model from making destructive WP-CLI calls.

I run a small WordPress agency and use this tool every day on client sites. If you're skeptical about agentic codegen for production infrastructure, the entire commit history is in the open β€” judge for yourself.


Why this exists

There are 25+ WordPress MCP servers on GitHub today. None targets the agency multi-site workflow with:

  • Real backup before every edit (postmeta via WP-CLI when SSH available, JSON file fallback β€” never silently lost)
  • Two-call confirmation for any destructive op (TTL 60s)
  • JSON validation + auto-rollback if an edit produces invalid Elementor data
  • 3-level CSS flush fallback (REST β†’ wp-cli native β†’ option/meta delete β†’ re-save)
  • Global widget awareness β€” preflight check warns if a page references shared widgets
  • WP-CLI escape hatch for everything the REST API can't do safely
  • Screenshots via headless Chrome (no puppeteer dep)

Configure

export ELEMENTOR_MCP_SITES='[{
  "id": "client-acme",
  "url": "https://acme.example.com",
  "username": "admin",
  "application_password": "xxxx xxxx xxxx xxxx xxxx xxxx",
  "ssh": {
    "host": "host.example.com",
    "user": "username",
    "port": 22,
    "path": "/path/to/wordpress",
    "wp_cli_path": "wp"
  }
}]'

Generate the WordPress Application Password at https://{your-site}/wp-admin/profile.php#application-passwords-section.

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.

wp_cli_path auto-detects if omitted (tries wp, then ~/bin/wp.phar, then ~/wp-cli.phar).

Claude Desktop config

{
  "mcpServers": {
    "elementor": {
      "command": "npx",
      "args": ["-y", "elementor-mcp-agent"],
      "env": {
        "ELEMENTOR_MCP_SITES": "[{\"id\":\"acme\",\"url\":\"https://acme.com\",\"username\":\"admin\",\"application_password\":\"...\"}]"
      }
    }
  }
}

Tools (34)

Sites & health

  • list_sites β€” enumerate the pool
  • ping_site β€” auth + version probe
  • site_health β€” multi-call health snapshot

Pages

  • list_elementor_pages β€” pages in builder mode
  • read_page_elementor β€” parsed summary + optional full tree
  • list_widgets_in_page β€” flat widget inventory with excerpts
  • list_global_widgets β€” shared widgets (edit one β†’ affects every page using it)
  • preflight_check β€” validate a page is safe to edit
  • elementor_find_replace β€” text replace with dry-run β†’ token β†’ apply β†’ backup β†’ validate β†’ rollback if invalid
  • list_elementor_backups / restore_elementor_backup β€” full restore chain with pre-restore safety backup
  • duplicate_elementor_page β€” clone within a site (data + page_settings + edit_mode)

Templates

  • list_elementor_templates β€” Theme Builder distinguished from regular library
  • export_elementor_template β€” portable JSON
  • import_elementor_template β€” drop into target site
  • apply_template_to_page β€” push template data onto an existing page

WP-CLI escape hatch (require SSH)

  • wp_cli_run β€” arbitrary wp-cli command with destructive-pattern detection + confirmation
  • wp_search_replace β€” wp search-replace with mandatory dry-run
  • wp_elementor_flush_css β€” 3-level fallback
  • wp_plugin_list / wp_plugin_update (with confirmation)

Visual

  • screenshot_page β€” headless Chrome PNG of any URL
  • compare_screenshots β€” SHA-256 + byte-delta

Widgets (v1.1 β€” widget-level CRUD)

  • read_widget β€” fetch one widget by id (read-only)
  • update_widget_settings β€” shallow-merge settings, with backup + validate + flush
  • delete_widget β€” remove a widget from its parent container
  • duplicate_widget β€” clone as sibling with fresh id
  • swap_widget_type β€” replace widgetType + settings, preserve id + position
  • add_widget β€” append a widget into a parent container
  • move_widget β€” move a widget between containers (with position)

Bulk & fleet (v1.1)

  • bulk_find_replace_site β€” find/replace across every Elementor page of one site, per-page backup + validate + flush
  • fleet_find_replace β€” same across every site in the pool (sequential, dry-run mandatory)
  • restore_from_file β€” restore _elementor_data from a JSON file backup, with pre-restore safety backup

Fleet

  • check_elementor_versions β€” flag outdated installs against wordpress.org latest

Post-write verification (v1.2)

Every mutating widget tool re-reads the page from canonical WP after the write and surfaces persisted state to the model. The HTTP write API can lie β€” return 200 OK while plugin filters or REST quirks silently drop the payload. This contract makes that observable.

Every applied response carries:

{
  "mutated": true,                  // false = no-op OR silent drop
  "warnings": [],                   // non-fatal issues
  "verification": {
    "method": "Re-read /wp/v2/pages/42 and check widget abc settings…",
    "reread_ok": true,
    "matches_requested": true,      // false = write API lied
    "persisted": { /* canonical state */ },
    "notes": "…explanation when something diverged"
  }
}

If verification.matches_requested === false, treat as a failure even if the HTTP layer said OK. The original payload survives in backup_meta_key β€” restore via restore_elementor_backup.


Safety guarantees

Hardcoded in src/elementor/policies.ts:

BACKUP_BEFORE_WRITE                 = true
BACKUP_PAGE_SETTINGS                = true
VALIDATE_JSON_AFTER_EDIT            = true
BLOCK_GLOBAL_WIDGET_WRITES_BY_DEFAULT = true
CONFIRMATION_TTL_SECONDS            = 60
GLOBAL_WIDGET_CONFIRMATION_TTL_SECONDS = 30
FLUSH_CSS_AFTER_WRITE               = true
MAX_ELEMENTOR_DATA_BYTES            = 5_000_000

And these wp-cli patterns are hard-blocked regardless of confirmation:

  • rm -rf
  • sudo *
  • db reset --yes / db drop --yes

End-to-end verified

v1.0.0 was tested in real conditions against a live WordPress install with Elementor 4.0.9:

  • βœ… 21/24 tools validated end-to-end
  • βœ… find_replace β†’ backup β†’ restore round-trip preserves data
  • βœ… duplicate_page copies data + page_settings + edit_mode
  • βœ… apply_template_to_page with auto-backup
  • βœ… wp_cli_run destructive flow (post delete) requires confirmation
  • βœ… screenshots identical detection via SHA-256
  • βœ… CSS flush uses wp elementor flush-css when SSH available, falls back to option-delete otherwise

7 bugs found during testing, all fixed:

  • REST API silently drops unregistered postmeta writes β†’ switched to WP-CLI primary for backups
  • wp not in SSH PATH on managed hosts β†’ auto-detection + wp_cli_path config
  • SSH post-quantum banner pollution β†’ stderr filter
  • Default Kit returned as "widget" β†’ client-side filter
  • _elementor_page_settings type object/string mismatch β†’ normalisation
  • Chrome cold-start screenshot timeout β†’ bumped to 60s
  • Templates listing same filter bug β†’ fixed

Roadmap

v1.1 βœ… shipped

  • Widget-level CRUD: read_widget, update_widget_settings, delete_widget, duplicate_widget, swap_widget_type, add_widget, move_widget
  • bulk_find_replace_site (across all Elementor pages of one site)
  • fleet_find_replace (across all sites in pool)
  • restore_from_file

v1.2

  • Global styles read/write
  • Theme Builder template push across sites
  • Section/column-level operations

v2.0

  • WooCommerce-aware tools
  • Visual diff (pixel comparison)
  • Schedule + cron scheduling

If this saved you time

The fastest way to support the project is a ⭐ star on GitHub β€” it helps other agencies running Elementor sites find this and tells me what to keep building.

You can also:

  • Open an issue for bugs, edge cases, or missing tools
  • Start a discussion for design or workflow questions
  • Share what you built with it β€” I'd love to hear