Our agents could already think. They could not reach a server.
That one gap is why most "AI-powered" operations still have a person sitting in the middle, pasting credentials and clicking deploy. The agent writes the plan. A human runs it. Call that what it is: a very expensive copy-paste job.
We closed the gap with thin MCPs, the smallest piece of code that gives an agent real server access and takes the laptop out of the path. This is the build log: the architecture, the two bugs a live run caught, the hosting constraint that killed our original plan, and the one component still blocked on a human. The strongest proof is the board itself: an SSH run at 10:16 found 29 plugins with 2 updates due, Chromium landed on the Sprite disk at 186.8MiB, and the build queue closed 4 of 7 parts by noon.
01 / a-thin-mcp-is-a-gate-not-a-brain
A thin MCP is a gate, not a brain
Model Context Protocol is an open standard for connecting AI applications to external systems. The specification defines three things a server can expose (tools, resources, and prompts), two transports (stdio for local processes, Streamable HTTP for remote ones), and a discovery step where the client calls tools/list before it calls anything at all.
What the spec deliberately does not decide is how much power you hand over. Wiz puts it plainly: MCP standardises how models discover and call tools and leaves authentication, authorisation, and transport security to whoever implements the server. The protocol is the wiring. The judgement is yours. Every MCP server architecture decision that matters sits in that gap.
So we made one: the gate holds the credential and the agent holds the judgement, and neither one ever holds both.
Three stops in the signal path, and only one of them thinks.
- The agent reads the account and decides what should happen.
- The gate authenticates and refuses anything off its allowlist.
- The server executes the named call and returns the result.

02 / what-is-inside-the-gate
What is inside the gate
Three layers, in order of travel.
The key. One credential per client, stored as an environment variable on the gate. The agent never receives it and never logs it. It cannot leak what it never holds. That is where the rest of the industry landed too: AWS ships OAuth for its own MCP server with short-lived tokens, and is explicit that authorising an agent grants it no additional permissions, because every request is still evaluated against your existing IAM policies.
The jacks. Named operations, spelled out. Ten tools on our WordPress gate. Seventy on the Vercel one. If there is no tool for a thing, the thing cannot happen. That list is the entire attack surface, which is the first time in this business anyone has been able to say the attack surface out loud as a number.
The guard. Snapshot before writing, health check after, revert on failure. This is enforced in the server, not requested in a prompt. No amount of prompt engineering skips a gate that lives in the code path.

Nothing clever lives in the gate. That is the design, not a shortcut. Anything smart belongs in the agent, where you change it by editing a sentence instead of redeploying code.
03 / a-gate-or-a-whole-computer
A gate, or a whole computer?
Two shapes cover almost everything.
A thin MCP when the job is one named API call. A deploy, a rollback, an env var, a plugin update. No state, no shell, no filesystem, and a blast radius you can read off the tool list.
A microVM when the job genuinely needs a computer. Ours is a Fly Sprite: a Firecracker microVM with a persistent disk that sleeps when idle and wakes on request. The disk is the whole argument, and it is better made with the real number than with an abstraction: Chromium lands once at 186.8MiB instead of being paid on every cold start, and the browser session survives between calls, which is what makes login-gated pages workable.

The rule we run on: destructive writes stay behind named operations. The computer is for open-ended work, not routine execution. Hardware isolation protects us; it does nothing for the client whose live site the SSH key on that box can reach.
04 / what-we-actually-built-and-what-broke
What we actually built, and what broke
Three components. The plan changed twice under contact with a real site.
WordPress: 10 tools, verified live
wp-admin-mcp covers plugin and theme state, site health, update history, and response checks, multi-tenant off environment variables so onboarding a client is three variables and no code change. We verified it against our own WP Engine test install rather than a fixture: WordPress 7.0.4, PHP 8.4.25, homepage returning 200 in 34ms, two plugin updates pending, and one premium plugin correctly flagged as blocked because it advertises a newer version and ships no download package. The morning run on the board is exactly the kind of evidence this post needed: SSH at 10:16, 29 plugins listed, 2 updates due.
Then the finding that rewrote the rollout plan.
On WP Engine, the web process can create a new file in wp-content/plugins but cannot overwrite an existing one. A plugin upgrade is an overwrite, so every REST-driven update dies at the copy step with Could not copy file. The identical upgrade run through wp-cli over SSH on the same site succeeds.
This is a false positive for every check you would normally run first. get_filesystem_method() reports direct. DISALLOW_FILE_MODS is false. is_writable() returns true. Writing a brand new file works. Only rewriting an existing file exposes it. That single behaviour eliminates the connector-plugin approach entirely, ours and the off-the-shelf alternative we read the source of, because both call the same Plugin_Upgrader::upgrade() that the host refuses.
Two more bugs surfaced only because we ran a real update instead of trusting the happy path:
- The upgrader reported success for an upgrade that never landed. Both
get_plugins()and opcache serve the pre-upgrade header inside the same request that did the upgrade, so the version read back unchanged and still looked fine. Success is now proven by re-reading the version from disk with opcache invalidated, and a version that did not move is reported as a failure. - The upgrader turned a plugin off and left it off. WordPress deactivates a plugin to swap its files; our search plugin came back inactive after a "successful" update. Activation state is now captured before and reasserted after, and a failed reactivation says so loudly instead of leaving a client's plugin silently disabled.
Vercel: 70 tools, deployed, waiting on a token
We forked an MIT-licensed open-source server instead of writing one. Upstream is stdio only, which our agent platform cannot connect to, so we added a Streamable HTTP route over the same seventy tools and left upstream's source untouched so the fork stays mergeable. tools/list returns all seventy with valid schemas, and the endpoint returns 401 without a token and 200 with one.
It is not doing real work yet. It needs a team-scoped API token, and we would not reuse a full-account credential on an endpoint that anyone holding the MCP secret can reach. That is a deliberate stop, not a delay.
The shared computer: provisioned on paper, blocked on a human
The Sprite that replaces the one machine everything used to depend on is written, scripted, and idempotent. It is blocked at step one on a browser login that only a person can complete, because the platform mints its own tokens through a browser and there is no server-side path around it.
We are saying that out loud because a status board that only shows green is not a status board.

05 / the-allowlist-is-the-security-model
The allowlist is the security model
MCP adoption has outrun MCP hygiene, and the numbers are not close.
- Research across 500+ scanned MCP servers found 38% had no authentication at all.
- A separate audit of 9,695 public MCP servers catalogued 4,982 security issues across 2,259 servers, including 2,054 instances of missing authentication, 880 cases of arbitrary file access, and 476 of command injection.
- Governance has not caught up either: only 21% of organisations have governance controls around non-human identities, while non-human identities outnumber people at 83% of organisations surveyed.
None of that is an argument against giving agents server access. It is an argument for the boring parts: deny by default, one credential per client, named operations only, short-lived tokens where the platform supports them, and a guard that lives in the code path rather than in a prompt.
Where this is genuinely weaker than a human, and we should say so: an allowlist cannot stop a well-formed but wrong instruction. If update_plugin is on the list, an agent that picks the wrong plugin will succeed at doing the wrong thing. The allowlist bounds the blast radius. It does not supply judgement. That is what the snapshot is for, and it is why anything destructive still ends at a person in our operation.
06 / what-this-actually-buys-a-team
What this actually buys a team
Every person on the team gets the same server access the founder has, and zero laptops sit in the deployment path.
Before this, the SSH keys, the deploy CLI, and the saved browser sessions all lived on one machine. If that machine was asleep, work queued behind it. That is a fine way to run a side project and a terrible way to run client sites. The gates move the capability off the hardware and onto an endpoint the whole team reaches, with a tighter permission model than the laptop ever had. It is the same layer we described in where MCP sits in the stack, now with a credential boundary in front of it.
The board compresses the win into three numbers: 4 parts done, 2 dashboard actions still on a person, and 0 laptops in the path. That is the whole point of the architecture.
07 / how-to-build-your-first-one
How to build your first one
- Pick a job that is already one API call. Deploys, rollbacks, status reads. If you cannot name the call, you do not want a thin MCP yet.
- Write the tool list before the code. That list is your MCP server architecture and your security review at the same time, and it is short enough to read in a meeting.
- Put the credential on the gate. One per client, scoped as narrowly as the platform allows. Never in the agent, never in a prompt, never in a query string.
- Make the guard structural. Snapshot, verify, revert, in the server. A rule in a prompt is a suggestion.
- Fork before you build. Our seventy-tool Vercel gate is someone else's open-source server with a transport bolted on. The custom build was the one nobody had already written.
Then run it against something real before you believe it. Every genuine finding in this post came from a live site, and none of them came from a test fixture. If you want the running cost of that decision, we published what agent access costs from our own books.