Skip to main content

yootheme-mcp

Three products from one repo — see PRODUCTS.md:

# Product Entry
1 Skill yootheme-remote skill/SKILL.md
2 MCP yootheme-mcp / python -m yootheme_mcp
3 CLI yootheme …

CLI (and optional MCP server) to manage YOOtheme Pro 5.x layouts, design settings, custom code, the new cookie consent manager and saved element presets on WordPress and Joomla 4/5 sites.

Talks to your sites via their standard REST API — no plugins, no MU-plugins, no SSH, no file-system access required on the remote side. Just an Application Password (WordPress) or an API Token (Joomla).

Status: beta. Package: yootheme-mcp 0.11.3 (MCP + CLI + Skill). Read-only tools and dry-run previews are free; writing to a site needs a licence key — see Licensing. What leaves your machine: see Privacy. Current prices and licence terms: https://fuerteventuratv.net/en/cms/yootheme-mcp

Two entry points

The package ships two console scripts after pip install -e .:

Command When to use it
yootheme ... Daily ops from a terminal (you, scripts, CI)
yootheme-mcp Run as an MCP server so Claude / agents can call the tools

The CLI is the recommended entry point. The MCP server is the same logic exposed to language models — useful if you want Claude Desktop to manage your sites in chat.

CLI quick reference

# discover what's configured
yootheme sites

# verify auth + reachability
yootheme ping tiserve

# list pages/posts/articles/modules — mark which have a YT layout
yootheme list tiserve --limit 50 --only-with-layout

# read a layout and save it to disk
yootheme get tiserve 32 --type page -o page32.json

# write a layout back
yootheme set tiserve 32 page32.json --type page

# copy a layout to another site (cross-CMS works!)
yootheme duplicate tiserve 32 staging-joomla 17 \
  --source-type page --target-type article

# bulk find/replace across every layout — dry-run by default
yootheme bulk-replace tiserve "https://old.example.com" "https://new.example.com"
yootheme bulk-replace tiserve "https://old.example.com" "https://new.example.com" --apply

# style customizer
yootheme customizer get tiserve -o customizer-backup.json
yootheme customizer set tiserve customizer-edited.json

# settings panel (custom CSS/JS, cookie consent, favicon)
yootheme settings get tiserve --key custom_less -o custom.less
yootheme settings get tiserve --key consent          # cookie consent manager
yootheme settings get tiserve --key scripts          # custom JavaScript list
yootheme settings set tiserve custom_less new-custom.less

# style customizer panels live under their own keys too
yootheme settings get tiserve --key style            # active style picker (e.g. "fuse")
yootheme settings get tiserve --key header.layout    # any Layout/Theme-settings panel

# saved element presets ("My Presets")
yootheme presets list tiserve
yootheme presets export tiserve my-grid-preset preset.json
yootheme presets import tiserve my-grid-preset preset.json

# Joomla-only: article CRUD
yootheme article create loquehay --title "New article" --catid 9
yootheme article update loquehay 42 --title "Renamed"
yootheme article publish loquehay 42
yootheme article delete loquehay 42              # -> Joomla trash (recoverable)
yootheme article delete loquehay 42 --permanent  # destroys it, no undo

# Joomla-only: media manager (list / upload / delete)
yootheme media list loquehay --path images
yootheme media upload loquehay ./hero.jpg --dest images
yootheme media delete loquehay images/hero.jpg

# Joomla-only: menus and menu items
yootheme menu types loquehay
yootheme menu items loquehay --menutype mainmenu
yootheme menu get loquehay 101
yootheme menu set loquehay 101 patch.json

# Joomla-only: list YT template styles + assignment
yootheme templates loquehay

# global flag: print machine-readable JSON
yootheme --json list tiserve --limit 5

Most write commands prompt for confirmation; pass --yes to skip. bulk-replace --apply, presets import and article create/publish/unpublish do NOT prompt — in particular --apply rewrites every matching layout on the site, so read the dry-run report first.

Feature coverage

Feature CLI / MCP support
Page layouts (sections / rows / columns) yootheme get/set/list/duplicate
Element library / element-level props edit via get + set
Element Presets (My Presets tab) yootheme presets list/export/import
Style Customizer yootheme customizer get/set
Custom CSS / Less (Settings panel) yootheme settings ... --key custom_less
Custom JavaScript (Settings → Scripts) yootheme settings ... --key scripts
Cookie Consent Manager (v5.0) yootheme settings ... --key consent
Favicon / Touch icon yootheme settings ... --key favicon / --key touchicon
Joomla modules with YT Builder layout --type module on get/set/list
Scroll-driven animations / parallax (v5.0) edit via get + set (MCP inspect_animations tool finds them)
Display Conditions, Menu Element, Date Filter, Margin/Padding splits, Multilingual switcher, lazy/on-click videos (all v5.0) inside the layout JSON — edit via get + set
Joomla article CRUD yootheme article create/update/publish/unpublish/delete
Joomla media manager yootheme media list/upload/delete
Joomla menus & menu items yootheme menu types/items/get/set
Joomla template styles + assignment yootheme templates
Pro Presets cloud library NOT exposed — admin-only
Child theme files NOT exposed — use SFTP

Customizer coverage map (vs. yootheme.com docs)

YOOtheme Pro's Customizer (tested against 5.0.x) groups everything into seven areas. They all serialize into one JSON config blob (Joomla: the template style's params.config; WordPress: /wp-json/yootheme/v1/style + settings), which customizer/settings get/set read and write by key. Mapping:

Customizer area (docs) Config key(s) How to reach it
Style → active style picker style (e.g. "fuse") settings get/set --key style
Style → Global / Theme / Inverse / component Less variables less (map of @variable: value) customizer get/set or --key less
Style → Google Fonts within less / style customizer get/set
Layout → Site & Logo site, logo settings --key site / logo
Layout → Header & Navbar header, navbar, top, bottom settings --key header …
Layout → Mobile header / off-canvas mobile, dialog settings --key mobile
Layout → Sidebar main_sidebar settings --key main_sidebar
Layout → Footer builder footer settings --key footer
Layout → Blog / Post / Category blog, post, page_category, search_module settings --key blog …
Menu (positions & items) menu (positions); Joomla menu items settings --key menu / menu cmds
Settings → CSS (custom Less) custom_less settings --key custom_less
Settings → Scripts (custom JS) scripts (list of descriptors) settings --key scripts
Settings → Consent Manager consent settings --key consent
Settings → Favicon / Touch icon favicon, favicon_svg, touchicon settings --key favicon
Settings → Advanced child_theme, media_folder, fontawesome, bootstrap, jquery, webp, lazyload, highlight settings --key <name>
Settings → External Services / API Key scripts prebuilt entries / provider keys settings get/set
Pages (per-page builder layouts) WP post_content / Joomla article fulltext JSON comment get/set/list/duplicate
Templates (styles + assignment) Joomla template styles templates
Modules Joomla module content --type module
Settings → Cache / System Check / Recompile / Download Less — (admin-only UI actions) NOT exposed

Every customizer/settings value is reachable through the generic settings get/set --key <dotted.path> (and customizer get/set). The only things with no REST surface are admin-UI actions (recompile, clear cache, download Less, system check) and the style library / cloud presets.

WordPress caveat (verified on Joomla only). On Joomla get_settings() and get_customizer() are the same config blob, so consent / custom_less / scripts are always reachable. On WordPress they are different REST endpoints (yootheme/v1/settings vs yootheme/v1/style), and the Settings shortcut tools (*_cookie_consent, *_custom_code) read and write via get_settings(). Confirm those keys actually live in the settings blob on your WP install before relying on the shortcuts — compare the read-only yootheme settings get <site> --key consent against yootheme customizer get <site>: if the key appears only in the customizer output, the shortcuts are reading the wrong store.

Install

Full English guide (this MCP + elementor-mcp): INSTALL.md
Windows quick path: extras/INSTALL_WINDOWS.md

From PyPI (MCP Marketplace buyers, or to try the free read-only tools):

python -m venv .venv && source .venv/bin/activate    # PowerShell: .venv\Scripts\Activate.ps1
pip install yootheme-mcp

yootheme --version           # prints the installed version
# Or on Windows (PowerShell), from the unzipped package folder bought on the GMC store:
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -e .

Windows step-by-step (config paths, Claude Desktop wiring): extras/INSTALL_WINDOWS.md.

Configure your sites

A single JSON file holds every site you want to manage. Path:

  • Linux/macOS: ~/.config/yootheme-mcp/sites.json
  • Windows: %APPDATA%\yootheme-mcp\sites.json

Or set YOOTHEME_MCP_CONFIG to a custom location.

{
  "sites": {
    "tiserve": {
      "platform": "wordpress",
      "url": "https://tiserve.it",
      "wp_username": "your-wp-username",
      "wp_app_password": "xxxx xxxx xxxx xxxx xxxx xxxx"
    },
    "loquehay": {
      "platform": "joomla",
      "url": "https://loquehay.es",
      "joomla_token": "base64TokenFromUserProfile"
    }
  }
}

See extras/sites.example.windows.json for a Windows-friendly starter file.

WordPress Application Password

  1. WP-Admin → Users → your profile → scroll to Application Passwords
  2. Name it yootheme-cli → Add New Application Password
  3. Copy the displayed value (format xxxx xxxx xxxx xxxx xxxx xxxx) — not shown again

Your normal admin login password does NOT work for the REST API. Application Passwords are core to WordPress since 5.6.

Joomla API Token

  1. Enable plugins API Authentication - Web Services Joomla Token and User - Joomla API Token
  2. Edit a Super User profile → Joomla API Token tab → Generate
  3. Copy the token as displayed (already base64-encoded)

WordPress native layout storage

YOOtheme Pro 5 stores its builder root in a JSON HTML comment in post_content. The default WordPress REST adapter reads editable raw content and replaces only that comment. Existing text before and after the comment is preserved, including the search excerpt; regenerate that excerpt in the YOOtheme builder if needed. Native layout access requires an account allowed to edit the target post, but does not require the bundled meta-exposer MU-plugin.

Versions through 0.10.1 used _yootheme_page meta and could report a successful write without changing the rendered page. A previous meta-only layout can be read for recovery; writing it to an empty page now creates native content. Converting a non-builder post requires explicit --replace-body / replace_body. That operation returns the replaced text: retain it alongside the layout backup. A non-default wp_meta_key retains custom meta integration behavior.

The optional SSH adapter still uses meta storage and has not received the native content correction. Use WordPress REST for native YOOtheme 5 page layouts.

On Joomla an article layout is an HTML comment at the start of fulltext, while a mod_yootheme_builder module stores its layout tree in content. Both are accessible via the Web Services API without any extra step.

A Joomla article's builder layout IS its body. YOOtheme renders it from an HTML comment at the start of fulltext, which has to be the whole body, so writing a layout onto an article that already has text replaces that text — irrecoverably, since the Web Services API keeps no version of it. set, import and duplicate refuse to do that and tell you so; pass --replace-body (CLI) or replace_body: true (MCP) to accept the loss. The replaced text comes back to you as replaced_body, and nowhere else.

Run as MCP server (optional)

If you also want Claude Desktop to call these tools in chat:

{
  "mcpServers": {
    "yootheme": {
      "command": "yootheme-mcp",
      "env": {
        "YOOTHEME_MCP_CONFIG": "C:\\Users\\<you>\\AppData\\Roaming\\yootheme-mcp\\sites.json",
        "MCP_LICENSE_KEY": "mcp_live_<your key - optional, enables the write tools>"
      }
    }
  }
}

Leave MCP_LICENSE_KEY out to run the free read-only tools and previews, or use YOOTHEME_MCP_LICENSE_KEY / license.key for a key bought on the GMC store (see Licensing). Run the server over stdio only: --http starts an HTTP transport with no authentication, for your own machine.

See extras/INSTALL_WINDOWS.md for the full Windows guide.

Licensing

yootheme-mcp is commercial software with a free read-only tier.

Without a key With a valid key
Read-only MCP tools (list, get, export, find, inspect, ping — 20 tools) yes yes
Read-only CLI commands (sites, ping, list, get, customizer get, settings get, presets list / export, menu types / items / get, media list, templates) yes yes
Previews (dry runs) of the write tools that have one — see below yes yes
Tools and commands that change a site (set, import, duplicate, replace, save, delete, upload, publish, patch — 21 tools) refused, with an explanation yes

Each tool is declared read-only or writing in the code, and the MCP annotations (readOnlyHint, destructiveHint) say the same thing to your client.

Free previews. Four write operations have a dry run, and the dry run is free: the MCP tools yootheme_replace_text, yootheme_replace_image and yootheme_bulk_find_replace (with dry_run left at its default, true), and the CLI command bulk-replace without --apply. A dry run reads the site and reports what would change; it writes nothing — not to the site, and no local backup either. While a free preview runs, the tool is technically unable to send anything but read requests. Applying the change (dry_run: false, or bulk-replace --apply) needs a key. No other tool has a dry run: a confirmation prompt (--yes) is not a preview.

Two kinds of key unlock the write tools; either one is enough:

Key Bought on Set it as Verified by
MCP Marketplace key (mcp_live_…) MCP Marketplace (mcp-marketplace.io) — annual subscription, equivalent to the GMC Solo tier (1 person) MCP_LICENSE_KEY in the environment of the MCP server or shell MCP Marketplace
GMC key https://fuerteventuratv.net/en/cms/yootheme-mcp — Solo, Base and Agency tiers YOOTHEME_MCP_LICENSE_KEY, or one line in license.key in the config folder (%APPDATA%\yootheme-mcp\ on Windows, ~/.config/yootheme-mcp/ on Linux) GMC Licenses

The prefix decides where a key is checked, so a key in the "wrong" variable still works. How the check behaves:

  • The key is checked the first time a write tool or command runs (and once when the MCP server starts, to report the status on stderr). A successful check is remembered on this machine — 24 hours for an MCP Marketplace key, 7 days for a GMC key — in a signed file that does not contain the key.
  • If the licence server cannot be reached, a successful check from the last 7 days still counts; otherwise write tools are refused until it can be reached. Read-only tools never need the network for licensing.
  • A key the server rejects (revoked, expired, replaced, unknown) stops the write tools at once; the read-only tools keep working.
  • There is no switch that skips the check.

Multi-seat and agency use: buy the Base or Agency tier on the GMC store. Full terms: LICENSE.

Privacy

yootheme-mcp runs on your computer. There is no telemetry.

  • Site credentials (WordPress Application Passwords, Joomla API tokens, SSH details) are read from your local sites.json, environment or env file and are sent only to the sites you configured.

  • Page content and layouts travel only between your machine and your own sites. Pre-write backups are written to your local disk.

  • Licence check: only the licence key and the product slug (yootheme-mcp) are sent, and only to the server that issued that kind of key:

    • MCP Marketplace keys → https://virupvwhtkpkjsiskckg.supabase.co/functions/v1/verify-key (MCP Marketplace's verification service, hosted on Supabase), as {"key": …, "slug": …};
    • GMC keys → https://fuerteventuratv.net (GMC Licenses, api.entitlement), as product and license_key query parameters.

    Like any HTTPS request, these also reveal your IP address to that server. Without a key, nothing is sent anywhere except to your own sites.

Architecture

yootheme_mcp/
  cli.py             # Click CLI (yootheme command)
  server.py          # FastMCP server (yootheme-mcp command)
  config.py          # sites.json + env-var config loader
  errors.py          # actionable error messages
  models.py          # Pydantic models
  license.py         # licence gate: free reads, key-checked writes
  adapters/
    base.py          # abstract adapter
    wordpress.py     # WP REST + Application Password
                     # auto-detect pretty vs Plain permalinks
    joomla.py        # Joomla Web Services + Bearer token
                     # supports article AND module object_types
  tools/             # MCP-only tools (sites, layouts, bulk, customizer,
                     # settings, presets, animations)
    _registry.py     # read_tool / write_tool: the one read-or-write declaration

Both cli.py and tools/*.py delegate to adapters/ — same REST code, two front-ends.

Changelog

  • On a multilingual Joomla site, yootheme menu set and the MCP tool yootheme_patch_menu_item unlinked the menu item from its translations: Joomla drops a menu item's language associations when a save does not send them, and it drops them for the whole group, so the English, Italian and Spanish versions of the item all stopped pointing at each other in the language switcher. The tool now sends the item's current associations back with every change, so a title or publish change leaves them as they were.
  • To unlink an item on purpose, send "associations": {} in the patch.
  • If you changed menu items on a multilingual Joomla site with an earlier version, check their Associations tab in Joomla (Menus -> the item -> Associations, or Components -> Multilingual Associations) and re-link the translations that lost their link. Single-language sites were not affected, and nothing else about the items changed.

v0.11.2 — bulk-replace scans a WordPress site once, every page

  • The CLI bulk-replace on WordPress re-read the same page of results instead of moving on (up to ~50 times), then usually stopped with 400 Bad Request when it asked for a page past the last one, without printing its report. It now reads each page of results once and each page and post exactly once.
  • If you ran bulk-replace --apply on WordPress with a replacement that contains the search text (for example foo -> foobar), the objects on a re-read page were rewritten more than once. Unless backups were turned off, each rewrite left a backup in your backup folder: the oldest backup of an object is its original state.
  • WordPress, pages and posts together (no --type, and the default of yootheme_bulk_find_replace): when one of the two ran out of pages before the other, WordPress answered 400 and the scan stopped (the MCP tool reported it as aborted). A type with no more pages is now simply finished.
  • Joomla, articles and modules together (no --type): the CLI bulk-replace could skip objects when one of the two had more than 50. With 60 articles and 5 modules, articles 51-55 were never scanned, so neither the preview nor --apply touched them. The MCP tool was not affected.

v0.11.1 — Previews (dry runs) are free

  • The dry run of yootheme_replace_text, yootheme_replace_image and yootheme_bulk_find_replace (the default, dry_run: true) and of the CLI bulk-replace (without --apply) now works without a licence key: see what a replace would change before you buy. Applying it still needs a key, and is refused before the site is contacted.
  • A free preview cannot write: while it runs, the WordPress and Joomla clients refuse every request that is not a read, the SSH backend refuses its write commands, and no pre-write backup is taken (a preview never took one).
  • The licence (section 1A) now includes previews in the free use.

v0.11.0 — Free read-only tier, licence enforced on writes, ready for PyPI

  • Licensing changed. The 20 read-only MCP tools and the read-only CLI commands now work without a key. The 21 tools and 14 commands that change a site need a valid key and refuse clearly without one — before any confirmation prompt and before any request to the site. Until 0.10.x a missing key or an unreachable licence server let everything run.
  • Two key types. MCP Marketplace keys (MCP_LICENSE_KEY, mcp_live_…) are accepted next to GMC store keys (YOOTHEME_MCP_LICENSE_KEY / license.key).
  • No more exit at start-up. A missing or rejected key no longer stops the MCP server or the CLI (exit code 2 in 0.10.x); the status is reported on stderr. yootheme-mcp --help no longer contacts the licence server.
  • Bypasses removed. The two environment variables that skipped the check or kept a rejected key running no longer exist and are ignored if set.
  • Signed licence cache. A successful check is cached in a signed file that holds a hash of the key instead of its last characters; an offline machine keeps write access for at most 7 days after the last successful check. The 0.10.x cache file is ignored and replaced.
  • Joomla tools annotated. The 12 Joomla tools now declare readOnlyHint / destructiveHint like the others, so MCP clients know which ones to confirm.
  • PyPI packaging. Wheel and sdist are built from the same allowlist as the customer zip and audited against it (scripts/build_pypi.py). New Licensing and Privacy sections in this README; server.json for the MCP Registry.

v0.10.2 — Native WordPress builder content

  • Read and discover YOOtheme 5 layouts from editable post content.
  • Write the native JSON comment and independently verify persisted content; preserve surrounding text and fail on missing edit access or ambiguous roots.
  • Keep automatic pre-write layout backups. Refuse conversion of non-builder content unless explicitly requested; return the replaced body when requested.
  • Escape HTML comment delimiters inside layout text and retain custom meta keys.
  • Correct stale package and price information in this README.

v0.10.1 — "local" is a hostname, not a word in the URL (security)

Read this before updating: a site entry that this client accepted until now can be rejected after the update. If any site in your sites.json (or .env) uses http:// for anything other than the loopback machine itself — localhost, 127.0.0.1, ::1 — or writes the credentials inside the URL (https://user:password@host/), the client will now refuse that entry with a configuration error instead of connecting. The fix is to give the site its real https:// URL and keep user and password in their own fields (wp_username / wp_app_password, or joomla_token). Nothing else about your configuration changes, and no data on any site is touched by this update.

  • The local-development exemption tested the whole URL, so remote sites could pass as local. This client allows plain http:// and relaxed TLS checking for a site running on the operator's own machine. That exemption was implemented as a text search for the loopback names anywhere in the URL string, rather than a test of the host the request actually goes to. A perfectly ordinary remote address could therefore satisfy it — for example because a loopback name happened to appear further along in the path, or because it formed the leading part of a longer, publicly registrable domain name. When that happened the client would talk to a real, remote site over unencrypted HTTP, or over HTTPS with certificate verification switched off — while still attaching the Authorization header (WordPress application password, or Joomla Bearer token) that it sends with every request. Anyone positioned on that network path could read the credentials, or present any certificate at all and be believed.
  • Now the decision is made on the host, not on the text. The URL is parsed and its normalised hostname compared against an exact set (localhost, 127.0.0.1, ::1). Both the WordPress and the Joomla transport ask the same single function whether to verify TLS, so the rule enforced when a site is loaded and the rule enforced when a request goes out can no longer drift apart. URLs that carry credentials in the userinfo part, that have no host, or that use a scheme other than http/https are rejected outright.
  • A configuration error quoted your password back at you. Pydantic renders the offending input value into its validation message; the config loader interpolated that message into its own error, and the MCP layer rendered it into the tool reply. So mistyping a field name — wp_app_passwordd for wp_app_password, say — made the value of that field part of the answer returned by yootheme_list_sites, a tool whose contract is that it never returns secrets. Validation errors now report only which field failed and why; the value is dropped. The two configuration models additionally set pydantic's own hide_input_in_errors, so a future validator cannot reintroduce the leak by accident.
  • New offline regression suites tests/test_loopback_transport.py (it inspects the SSL context the HTTP client actually built, for both adapters, without opening a socket) and tests/test_config_error_redaction.py (a canary value, with a negative control that proves the leak is real when the fix is removed). Suite: 126 tests, all passing.

Coming from a 0.9.x release? Two earlier changes matter more than this one. 0.9.2 fixed a fresh install that could not start the MCP server at all: the mcp dependency had no upper bound, so a new pip install resolved a 2.x release that no longer contains the module the server imports, and python -m yootheme_mcp — the exact command in the Claude Desktop configuration — died on import while the yootheme CLI kept working. 0.10.0 gave every write path a backup: a YOOtheme layout is versioned by neither WordPress nor Joomla, so before that release a set, import, duplicate or find-replace through this client was final. Each write now snapshots what it replaces and returns the path as backup_file; re-importing that file is the undo. Install as usual — unpack the zip over a fresh directory and run pip install -e . in it (full steps in INSTALL.md), then confirm with yootheme --version.

v0.10.0 — A half-failed write now leaves something to go back to

  • An overwrite was final, and the tool said otherwise. yootheme_set_layout told the operator "on WordPress this is destructive but WP revisions usually allow recovery". It is not true: a YOOtheme layout lives in post meta on WordPress, and WordPress does not carry post meta into revisions; on Joomla it lives in an article's fulltext or a module's content, which have no builder versioning either. So neither platform could undo a set / import / duplicate / find-replace done through this client — the one product of the three (yootheme-mcp, elementor-mcp, gmcbuilder-mcp) with no backup and no restore. Every write path now snapshots the layout it is about to replace to disk first and returns the path as backup_file; feeding that file to yootheme_import_layout is the undo. Default ~/.yootheme-mcp/backups, override with YOOTHEME_BACKUP_DIR.
  • A backup that cannot be taken now refuses the write instead of proceeding quietly — a safety net nobody can tell is missing is worse than none. Set YOOTHEME_BACKUP=0 to accept the loss deliberately. Likewise a read that fails for any reason other than "there is no layout here" blocks the write: a site that cannot be read reliably must not be overwritten blind.
  • A site-wide replace that died half way threw away the list of what it had already changed. yootheme_bulk_find_replace writes one object at a time and is not atomic; when the paging call timed out at object 51, the 50 layouts already rewritten on the live site were reported as a single line reading Error: Request timed out. The per-object report is now always returned, with aborted, aborted_error, objects_committed, and a backup_file per committed object.
  • yootheme bulk-replace --apply asks before committing (--yes to skip). It rewrites every matching layout on a whole site and had no prompt at all. yootheme presets import asks too — it overwrites any preset of the same name.
  • New regression suite tests/test_failure_recovery.py (14 tests) drives the destructive paths against a transport double that fails exactly where told: mid-page timeouts, refused writes, an unwritable backup directory.

v0.9.9 — The shared install guide names the twin's real versions

  • INSTALL.md (the guide mirrored with elementor-mcp) still described elementor-mcp 0.5.0: it pointed at the companion zip gmc-elementor-mcp-0.5.0.zip under the vendor's dev path D:\elementor-mcp\..., promised a ping answer of plugin_version 0.5.0, and the versions table was three elementor releases behind. A reader following it would fetch a superseded companion from a folder that only exists on the vendor's machine and then judge a correct install broken when ping answered a different number. Re-synced to the elementor-mcp 0.5.6 mirror (the twin fixed its copy in its own 0.5.6 release): the companion is gmc-elementor-mcp-0.5.1.zip shipped inside the elementor package, ping answers 0.5.1, and the versions note records that client (0.5.6) and companion (0.5.1) move independently. Docs-only — no code changes.

v0.9.8 — The delivery zip tells the truth about itself

  • The 0.9.7 zip shipped a README that said 0.9.6 (no 0.9.7 changelog either): the zip was built from the tree before the release docs were committed. Docs are now aligned and the zip is rebuilt from the committed tree, so the package a customer opens names the version it actually is.
  • Install docs told you to run INSTALL.ps1 — a file the zip deliberately does not contain (it is the vendor's personal installer, excluded by the packaging allowlist since 0.8.3). README / INSTALL.md / PRODUCTS.md now give the real steps: pip install -e . plus the shipped extras/INSTALL_WINDOWS.md guide.

v0.9.7 — Windows APPDATA paths + MEDIUMTEXT ops

  • Licence / default sites.json on Windows use %APPDATA%\yootheme-mcp\ (aligned with docs).
  • scripts/alter_mediumtext.sql shipped for sites still on TEXT 64KB; local jtest54 modules raised to MEDIUMTEXT.

v0.9.6 — Unified MCP/CLI/Skill package + soft licence check

  • One storefront SKU / one zip: MCP + CLI + agent Skill (skill/).
  • Soft licence check against GMC Licenses (api.entitlement); key in %APPDATA%/yootheme-mcp/license.key or YOOTHEME_MCP_LICENSE_KEY.
  • MCP Joomla ops parity: article CRUD, media, menus, templates (clear error on WordPress).
  • Layout schemas document Joomla module (production path).
  • List price EUR 39 one-time (was 29). Existing keys stay valid.

v0.9.5 — ArticleHelper-faithful article layouts + Pro 5.0.37

  • Article has_layout / list use the leading <!-- {json} --> fulltext comment only (attribs mirror is write-only BC — no more false positives after body wipe).
  • Serialize forces single-line compact JSON; extract matches ArticleHelper::PATTERN (start-anchored, no DOTALL).
  • List requests text + fulltext for articles; clearer "no layout" errors.
  • WordPress adapter: verify=False on localhost (parity with Joomla).
  • Docs target bumped to YOOtheme Pro 5.0.37.

v0.9.4 — Reliable failures, bulk operations and Joomla module layouts

  • Failures are no longer reported as success. Joomla discovery now raises when every endpoint fails, WordPress settings writes verify that a real YOOtheme option changed, SSH list failures surface, and preset deletion reports whether anything was actually removed.
  • Bulk operations preserve a truthful report. Read and write failures are returned per object, partial progress is retained, pagination terminates correctly, and the SSH backend can scan beyond its first page.
  • Joomla builder modules now use their real storage. Reads and writes go through the module content field used by mod_yootheme_builder; the old params.yootheme_pro value remains only as a compatibility mirror.
  • CLI and settings correctness fixes. Bracket-indexed settings paths can be written, --http --port honors the requested port, and multi-site bulk inserts the site argument in the right position.
  • Safer operator messaging. Recursive media-folder deletion is described as permanent, commands that intentionally skip confirmation are documented, and the customer ZIP no longer refers to files it does not ship.

v0.9.3 — The install example printed the old version too

  • The Install section showed yootheme --version returning 0.8.2. 0.9.2 fixed the version the command prints but not the one the documentation promises, so the first thing a reader checks after installing still showed the superseded number — the same defect, one layer over. The example no longer pins a version literal at all, and a test refuses one, because a number restated in prose is a number that drifts.

v0.9.2 — A fresh install starts the MCP server again

Packaging, plus four more destructive-path defects — two of them introduced by the fixes in 0.9.0 and 0.9.1.

  • article update --text destroyed a builder layout. The mirror image of what 0.9.0 fixed in the other direction: the read-more split sends fulltext: "" whenever the new body carries no marker, and fulltext is where an article's layout lives. The page reverted to plain text with no copy anywhere, while list/get_layout kept reporting a layout because they fall back to attribs. Now refused unless replace_layout is passed.
  • A failed trash was reported as trashed. article delete tolerates 400/409/422 because an already-trashed article answers that way — but on the trash-only path it then returned {"trashed": true} after a PATCH that had failed, so the article sat live and untouched while the operator was told it was in the trash. Only the destroy path may treat that as harmless.
  • set --replace-body discarded the body it promised to hand back. It was returned "in the JSON output and nowhere else", and the default human mode has no JSON output at all. The replaced body is now written to a file beside the layout — or printed when there is nowhere to put it — in every mode, and duplicate surfaces it too.
  • The scripts-removal guard had a type-shaped hole. It only ran when the value was a Python list, so a JSON-encoded string or a single descriptor dict skipped the check and replaced the whole list while reporting wrote: true. The value is normalised before the diff; anything that cannot be a scripts list is refused rather than written.
  • mcp[cli] had no upper bound, and mcp 2.x removed mcp.server.fastmcp. A virtualenv created today resolved mcp 2.0.0, so python -m yootheme_mcp — the command in the Claude Desktop configuration — died at import with ModuleNotFoundError. The terminal CLI kept working, because it never imports the server: the failure was invisible from the command line and total in Claude Desktop. The requirement is now >=1.2.0,<2.
  • yootheme --version reported 0.8.2. __version__ had stayed behind while the package moved to 0.8.3, 0.9.0 and 0.9.1, so the CLI named the version the customer had just replaced. Both are now covered by tests/test_packaging_contract.py, which asserts the declared range and the version string rather than the local environment — the environment is what hid the first defect.

v0.9.1 — A scripts write can no longer delete what it omits

  • yootheme_set_custom_code(kind='scripts') replaced the entire list, so any script or External-Services entry the caller left out was deleted from a live site. The docstring said so; nothing enforced it, which makes it a trap rather than a warning — and an agent composing a list from memory drops entries very easily. The write is now refused when it would remove existing entries, naming them in would_remove; allow_removals: true accepts the loss and hands the removed descriptors back as removed. Adding entries needs no flag.

v0.9.0 — Destructive commands stop lying

Three ways this tool could destroy work while reporting success. Each one is covered by a regression test in tests/test_destructive_commands.py.

  • article delete destroyed the article while promising the trash. Its confirmation read "Joomla trashes it first, second delete is permanent", but the implementation ran the trash and the permanent delete in that one confirmed command. The operator was told the article was still recoverable; it was already gone. Delete now trashes — recoverable from Joomla's trash — and destroying needs --permanent, whose prompt says exactly that.
  • set --type article blanked the article body. A Joomla article's builder layout has to be the entire body (an HTML comment at the start of fulltext, with introtext empty), so writing a layout onto an article that had text replaced that text, silently, with no version to restore from. Writing a layout over a body is now refused; --replace-body / replace_body: true accepts the loss and returns the previous body as replaced_body. Editing an article that already has a layout is unaffected — no flag needed.
  • Every write through the SSH backend failed. _wp_stdin passed a literal - as the value, on the belief that WP-CLI reads stdin when it sees a dash. It doesn't: wp post meta update <id> <key> [<value>] and wp option update <key> [<value>] read stdin when the value is omitted, so the dash was stored as the value — and under --format=json a bare - is invalid JSON, so the command errored. The command line is now built in one place, so a second copy cannot drift away from the first again.
  • Also: the SSH runner waited for the remote exit status before draining stdout, which deadlocks whenever output exceeds the channel window — wp option get yootheme on a real site is comfortably that big.

v0.8.2 — Settings and Joomla article updates

  • Fix: Settings convenience accessors used wrong YOOtheme Pro 5.x keys. Verified against live Joomla 5.x sites and the yootheme.com Settings docs, the real config keys are consent (Cookie Consent Manager), scripts (custom JavaScript, a list of descriptors) and custom_less (Settings → CSS). The tool previously used cookies, head_scripts/body_scripts and custom_css — keys that don't exist in the config, so yootheme_get/set_cookie_consent and the head/body/css custom-code shortcuts were silent no-ops (get returned {}, set wrote dead keys). Now: cookie-consent reads/writes consent (with a cookies read-fallback); the custom-code kind is css/less → custom_less and scripts → the JS list. The generic settings get/set --key <path> was already correct (it operates on raw keys); only the docs/help examples were updated to match. Added a Customizer coverage map to the feature docs cross-referencing every customizer area against the yootheme.com documentation.
  • Fix: Joomla article update body edits now persist. The update path sent the new body under articletext, but Joomla's JSON Web Services API ignores that key on PATCH (it's a form-layer alias) — the request returned HTTP 200 and bumped modified/version while leaving the stored body unchanged. The update path now remaps articletext → introtext (the writable model field). CREATE is unaffected (it still accepts articletext).

v0.8.0 — Packaging & SSH adapter

  • New WordPress SSH adapter (wordpress_ssh.py): routes WordPress sites with ssh_host configured through wp-cli over SSH instead of the REST API.
  • Project packaged as a distributable wheel + sdist (python -m build).
  • Canonical version is now declared once in pyproject.toml and re-exported as yootheme_mcp.__version__.

v0.4.0 — CLI-first

  • New yootheme CLI as the primary entry point.
  • Removed status=any from the default page listing (was triggering HTTP 400 on sites without elevated REST permissions).
  • MCP server still ships under yootheme-mcp for Claude Desktop integration.
  • README rewritten around CLI usage; MU-plugin downgraded from required to optional workaround.

v0.3.0 — Real-world hardening

  • WordPress: auto-detect of pretty vs Plain permalinks (auto-fallback to ?rest_route=).
  • Joomla: new object_type='module' alongside 'article'.
  • extras/ folder with mu-yootheme-rest.php, Windows config samples and install guide.

v0.2.0 — YOOtheme Pro 5.0.34 coverage

  • Tools for Settings panel, Cookie Consent Manager, Element Presets, scroll animations inspector.

v0.1.0

  • Layouts, Customizer, bulk find/replace, WP + Joomla adapters.

License

Commercial, sold per licence through GMC Licenses and MCP Marketplace — see LICENSE. The read-only features may be used without a key (see Licensing). Not open-source: you may use and modify it for your own sites, but not redistribute or resell it. The bundled WordPress companion extras/mu-yootheme-rest.php is GPL-2.0-or-later. Third-party Python dependencies keep their own licences.

Metadata

Release files for yootheme-mcp 0.11.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for yootheme-mcp 0.11.3
File Size Uploaded
yootheme_mcp-0.11.3.tar.gz 118.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for yootheme-mcp 0.11.3
File Interpreter ABI Platform
yootheme_mcp-0.11.3-py3-none-any.whl Python 3 none any Details

Total release size: 216.8 kB

Release files / yootheme_mcp-0.11.3.tar.gz

Download URL yootheme_mcp-0.11.3.tar.gz
Size 118.4 kB
Tags Source
SHA-256 checksum
How to use checksums
8bb164ad40ea81dd01f9832adf2cbf604526cef00211f9cb6450036a8024c2af
BLAKE2b-256 checksum
How to use checksums
5bbfe758227cf3ea0bb7296f8083c82099af5925238bb7d7898bb41a52b43fb2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.11

Release files / yootheme_mcp-0.11.3-py3-none-any.whl

Download URL yootheme_mcp-0.11.3-py3-none-any.whl
Size 98.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2f96386d1c95ecbb920b9611610956f2bfc3a4c69dbf9e7908a86afb5ed6a283
BLAKE2b-256 checksum
How to use checksums
1ec5963fae4e3aa9e30d5a653bbc8809f1d8f735d8f4efbf53dca413104d02ce
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.11

Release history Release notifications | RSS feed

This release

0.11.3 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page