Claude earned your trust in code. Bring it to WordPress.
WP MCP Server previews every WordPress write, then holds it for approval from someone other than the person who asked for it.
Self-hosted core. WP MCP Cloud never holds your SSH keys or site credentials.
Your code gets a diff and a reviewer. A live WordPress option gets neither.
Point Claude at a client's WordPress install, and one prompt can change a live option instantly. No diff. No PR. No second reviewer.
Three steps, and the exact walkthrough lives in the docs.
docker compose up -d) or pip install -e .. It comes up on 127.0.0.1:8642, bound to loopback — nothing outside your machine can reach it.site_register at a site over SSH+WP-CLI, or install the companion plugin for sites where you only have plugin access.claude mcp add command with a scoped bearer token — or drop the same config into .mcp.json if you'd rather commit it to the repo.$ claude mcp add --transport http wpguard http://127.0.0.1:8642/mcp \
--header "Authorization: Bearer <TOKEN>"
Full read access. One guarded gate before anything writes.
Investigate without limits
Claude can pull core version, active plugins/theme, options, and post meta anytime — no packet, no waiting. Recon output is wrapped as untrusted content, so Claude never mistakes what it reads for an instruction.
Every write starts as a preview
Option updates, post-meta edits, content search/replace — Claude proposes all of them with apply=False first. Nothing reaches the live site without an approved packet.
Raw PHP stays out of reach
wp_eval exists for the rare case you truly need it, but it's admin-scoped, SSH-only, and never the path Claude reaches for by default.
Treat a WordPress write like a pull request: someone else signs off before it merges.
A developer can ask Claude to draft the change end to end. A second person still reviews the exact preview and approves the packet before it can execute.
packet_open(summary="Update tagline for spring promo",
risk="low", verb="wp_mutate_option", …)
→ status: proposed
packet_approve(packet_id="a1b2c3", approver="connor")
→ status: approved
// the proposer and the approver can be different people
Even a stale write gets refused, automatically.
If someone else changes the live value after Claude previewed a change, the write fails at execution. It never silently overwrites what changed underneath it. Pass the dry-run's etag back as expected_etag, and a stale write fails closed automatically.
The same digest binding refuses execution if a packet's arguments were tampered with after approval. An approval that no longer matches what's about to run simply doesn't count.
Before you connect Claude, you'll probably ask
-
"Claude Code already confirms before it runs anything risky."
That confirmation goes to whoever's driving the session. WP MCP checks approval on the server itself, so it holds even if one person does both jobs.
-
"Reviewing every read will slow me down."
Recon, options, post meta, and cache-bust all run with no packet and no wait. Only a real write pauses for a preview and a second signature.
-
"I don't want another vendor holding my client's SSH keys."
wpguard-mcp runs on your own infrastructure. WP MCP Cloud never touches customer sites or holds SSH keys or credentials.
Also using Cursor or Codex?
Same guard, same packets, same evidence trail — whichever MCP client your team standardizes on.