Limited-time launch offer 20% off Pro — first payment and every renewal — with code See pricing

The protocol

MCP is not just JSON-RPC with a new name.

It runs on JSON-RPC 2.0, which is a message envelope and nothing more. What MCP adds on top is the part that decides whether an agent pointed at your WordPress site behaves predictably or guesses.

Written from the plugin's own gateway. Where the protocol stops and SiteHelm's policy starts is marked, because the difference is the whole point.

 · 5 min read

JSON-RPC 2.0 is about a page and a half of specification, and almost all of it is about the shape of an envelope. A request carries a method name, some parameters and an id. A response carries a result or an error against the same id. That is the whole contract. What the method names mean, what the parameters are allowed to be, which of them exist on this particular server — none of that is in the specification, because none of it is the specification’s job.

That works when one team owns both ends and can hard-code every detail. It stops working the moment the client is a general-purpose agent and the server is somebody’s WordPress install, because now the client has to find out what it is talking to before it can do anything useful. This is the gap MCP fills, and it is worth being precise about what goes in it, because “MCP is just JSON-RPC” is both technically true and completely misleading.

Four things go on top of the envelope

Capability negotiation. The connection opens with an exchange in which both sides say what they support before a single tool is called. The client learns whether the server offers tools at all, whether it offers resources, whether it can send notifications. Nothing is inferred from a version number.

Runtime discovery. The client asks the server to list its tools, its resources and its prompts, and gets back the list this server has right now. On a WordPress site that is not a nicety. A site with Elementor exposes things a site without it cannot; a site where the owner has switched a module off should not be advertising the operations inside it. Discovery is how the server tells the truth about itself instead of the client acting on a list that was accurate somewhere else.

A typed schema on every tool. Each tool carries a JSON Schema describing its input. The client uses it to build a valid call; the server uses it to reject an invalid one. That sounds like documentation and is not: it is the difference between a wrong argument being caught at the boundary and a wrong argument reaching a WordPress function that will happily do what it was asked.

A session. The connection has state and lasts longer than one request, so a workflow can be several steps — read, plan, check, act — without pretending to be a single call or inventing a correlation scheme of its own.

None of those four is exotic. Every one of them is something integrations have always built by hand, badly, one project at a time. Standardising them is the contribution.

Why the typed schema is the one that matters most here

A live WordPress site is not an environment where a malformed call is free. If an agent sends the wrong post id, a page that had content now has different content. If it sends the wrong menu, the navigation moves. There is no test database underneath catching it.

JSON-RPC will tell you a parameter was not valid JSON. It has nothing to say about whether postId is required, whether status may be the string you sent, or whether the two arguments you sent together contradict each other. So an agent working over bare JSON-RPC finds out what is valid by trying, and on a live site trying is the expensive part.

SiteHelm’s gateway takes the same position one layer further in. Every operation declares an input schema, arguments are validated against it before anything touches WordPress, and a violation comes back as a typed refusal — InvalidInput — whose message names the key that was wrong. A refusal is a cheap outcome. A half-applied write is not.

Where the protocol stops

Here is the part that gets skipped in most explanations of MCP, and it is the part that decides whether your site survives the experiment.

MCP standardises how a client and a server describe what is available. It does not decide what a tool is allowed to do. It has no opinion on whether a write is reversible, whether the acting user was checked, or whether anything was recorded. A server that exposes “run this SQL” as a tool is a perfectly conformant MCP server. Conformance is not a safety property.

So the useful question about any MCP server pointed at a site you care about is not whether it speaks the protocol. It is what the server does with a call once the protocol has handed it over. Ours answers it like this:

  • Operations are typed and grouped by dispatcher, so what an agent can attempt is a fixed list rather than whatever the REST surface happens to expose.
  • Every write is preview-then-apply. The first call returns a plan describing what would change. The write happens only on a second call carrying the single-use token that plan produced, with byte-identical arguments — reuse the token, change the arguments, or leave it too long and the answer is StalePlan rather than a write.
  • Each operation declares the WordPress capability it needs, and the handler checks that capability again itself against the acting user rather than trusting that something upstream did.
  • Writes are snapshotted before they land and can be rolled back from the audit ledger in wp-admin.
  • Every call is written to that ledger, refusals included.

Not one of those five is required by MCP. They are the reason the plugin exists. The protocol got the agent to the door in a predictable shape; everything after the door is policy, and policy is what you should be reading before you connect anything to a site with customers on it.

What this means when you are choosing something

If you are evaluating an MCP integration for WordPress, “it supports MCP” tells you the client will be able to enumerate the tools and construct calls without guessing. That is genuinely worth having. It tells you nothing at all about what happens when one of those calls is wrong.

Ask the second set of questions instead. Is there a preview step, and is the authority to write bound to the preview you actually read? Is the change snapshotted, and can you put it back without a database restore? Does the server re-check the capability of the acting user per operation, or was permission settled once at connection time? Is there one place you can read afterwards that shows what was attempted, including the things that were refused?

The protocol is the easy half. It is the half that has a specification.

Questions

The questions this raises

Is MCP a different wire format from JSON-RPC 2.0?

No. MCP messages are JSON-RPC 2.0 messages. What MCP defines is the layer above the envelope: an initialisation handshake in which both sides declare capabilities, methods for listing tools, resources and prompts, a JSON Schema on every tool's input, and a session that survives more than one call.

Does MCP make an integration secure?

No, and treating it as a security layer is the common mistake. MCP decides how a client and a server describe what is available. What a tool is permitted to do, who it checks that against, and whether a write can be undone are all decisions the server makes. A badly built MCP server is exactly as dangerous as a badly built REST endpoint.

Why do typed tool schemas matter more on a live site than in a sandbox?

Because a malformed call on a live site is not a failed test, it is a changed page. A schema on every input lets the client build the call correctly the first time and lets the server refuse a wrong one before it reaches any WordPress function, with a message that names the offending key.

What is runtime discovery for?

So the client stops assuming. Two WordPress sites are never the same shape — different plugins, different page builder, different fields. Discovery lets the server say what exists on this site right now, rather than the client acting on a list that was accurate on somebody else's install.

Next

Read the thing itself.