I do WordPress and SEO work for clients. I wanted Claude to operate my sites, but I did not trust an agent with raw database access. So I spent the last year building SiteHelm: a GPL plugin that exposes a WordPress site as 115 typed MCP operations - content, media, menus, Elementor, ACF, SEO plugins.
The safety model is the whole point, so here it is:
Two-phase writes. Every write is two calls. The first is a preview: it writes nothing and returns each field's before and after value with a single-use plan token. The apply is bound to those exact arguments - change one and it is refused. The diff you approved is the diff that lands.
Snapshot and verify. Before a write, the engine records everything a restore would need. After it, the site is read back and compared with the preview's promise. A mismatch is reported as a failure, not a success. This read-back step is where the real bugs hide - a WordPress write can return success while saving into a row the renderer never reads (Elementor is famous for this).
Audit and rollback. Every change lands in a log in wp-admin, in plain sentences, and applied changes roll back from there - with a preview first.
No escape hatches. The agent gets named operations with strict input schemas. It does not get PHP, SQL, a shell, or the filesystem. Plugins install only from WordPress.org by slug, land deactivated, and the owner can pause every write with one switch the agent cannot reach.
Repo: https://github.com/Mrshahidali420/SiteHelm - site: https://wpsitehelm.com
It is free and open source (there is a paid add-on for WooCommerce and Elementor Pro surfaces, which is how I keep it sustainable). I would genuinely like feedback on the two-phase write contract - especially from anyone building write-capable MCP servers.
Top comments (2)
The read-back step is the part most write-capable servers skip, and it is the only one that catches the class of bug you named -- a write that returns success while saving into a row the renderer never reads. We hit the same shape on a smaller scale with a headless browser: a form submit that 200s and a state change that never landed, and no amount of inspecting the response told us apart from a real change. The only reliable signal was reading the consumer afterwards.
On the two-phase contract: binding the apply to a single-use plan token plus the exact previewed arguments is the right shape, and it raises one question I'd want your take on. What happens when the state moves between preview and apply -- someone edits the same post in wp-admin, or a plugin fires on save? Do you re-validate the before-values at apply time and refuse on drift, or is the token only binding the arguments and the last writer wins? The first is stricter but makes long preview windows painful; the second is easier and leaves a window where the approved diff is no longer the diff that lands.
Some comments may only be visible to logged-in visitors. Sign in to view all comments.