Are Local MCP Servers Dead?
In March I published a post about wiring a local MCP server into my blog’s skills, so that a cover image could be generated without leaving the terminal. It ended confidently: identify the manual gap, find an MCP server that fills it, wire it into your skill.
This week I uninstalled that server. It had worked; then it stopped connecting, silently, at startup, and I never noticed the moment. What replaced it is a script of under a hundred lines that makes one HTTPS call, invoked from the same skill.
A small embarrassment, except that it’s also my day job now: I govern coding agents inside a company, and the first real argument that policy produced was about exactly this.
The Policy
The fleet is mixed. Some developers live in Claude Code in a terminal. Many more people, developers and non-technical colleagues alike, use the desktop app, some of them through its coding tab, which is the same agent with a shell behind a friendlier face.
For all of them the set of MCP servers is fixed: a short curated list, nearly all of it remote servers, most behind a proxy we run because a proxy is where monitoring and audit logs live. The list is pushed to every machine through device management and pre-approved by managed settings, so a colleague who has never heard the word “protocol” can update a wiki page without seeing a configuration file or a prompt. Security likes it; the non-technical users don’t know it exists, which is the highest compliment a platform gets.
And every local MCP server is forbidden.
That annoyed some developers, and their demand was legitimate: a tool they’d built that parses a legacy codebase into a syntax tree so the agent can query it and retro-document it. Useful, implemented as a local MCP server, a jar on their machines. I said no, and they made the objection any good engineer makes:
The agent has bash. If a prompt injection wants to do damage, it doesn’t need our MCP server. Blocking local MCP changes nothing.
Endorsement, Not Containment
They’re right about containment. Developers here have an open shell; my policy contains nothing they choose to run, and the alternative I pushed them toward — a script inside a skill — is exactly as swappable as their jar, with no signing story either: Snyk counted 1,467 malicious payloads in one public skills marketplace this February.
But look at what putting their server on the list would mean: an entry in a managed file saying this command line is approved, for everyone, without asking. Claude Code’s documentation matches a local server by “the exact command and arguments that start a stdio server”; “commands match exactly. Every argument, in order.” Matching by name “is not a security control,” because anyone can call any server github. GitHub Copilot’s enterprise allowlist, shipped this August, has the same keys and the same caveat. Cursor’s matches “the full command string,” and its own documented example entry is, I promise, npx -y @acme/mcp-tool@latest.
Nothing in any of them mentions a hash, a signature or an owner. The allowlist approves a string. It does not approve the code that runs. java -jar /some/path/tool.jar is approved forever, whatever that jar becomes; an approved @latest is an approval of whatever gets published next. The first malicious MCP server found in the wild, postmark-mcp, shipped fifteen clean versions and then one that, per Snyk’s diff, added a single line: a Bcc: to the author’s address on every email the agent sent. Nobody who approved that server approved that line.
When a developer runs their own script behind their own permission prompt, accountability sits where the knowledge sits. When I put their jar on the list, I’ve stamped an artifact I can’t pin, on behalf of a whole company that was promised it would never have to evaluate what runs. Governing MCP was never about what a developer can run. It’s about what the organization silently vouches for. The policy sounds like “you can’t be trusted with this.” It means “I can’t sign this, because the thing I’d be signing isn’t the thing that runs.”
(A narrower, technical point, kept narrow: a script runs through the agent’s Bash tool, in the transcript, under permission rules and inside the sandbox if one is on. The sandbox documentation is explicit that it “applies only to Bash, PowerShell, and Monitor commands and their child processes,” and describes an MCP server as something the agent “runs outside the sandbox.” Real, but the second argument.)
The Harness Decides
There’s a wave of posts this year announcing that MCP is dead and a good CLI will do. They miss the point from the other side, because of the thing nobody in that debate mentions: the client the agent runs in.
Take the desktop app my colleagues use. Its chat tab has no shell. Files Claude makes there come back “as downloads”, not written to disk, and its code execution happens in a hosted sandbox rather than on the laptop. A remote connector “connects to your MCP server from Anthropic’s cloud, not from your local device,” through per-user OAuth an owner can scope and revoke from the identity provider. In that harness MCP isn’t one option among several; it’s the only way the agent reaches anything, and the machine is never in the blast radius. That’s where MCP shines — and everything it is uniquely good at, credentials kept out of the context, zero install, a server maintained by whoever owns the API, a gateway to stand at, is a property of a remote server. Charles Chen put it bluntly in the best piece I read on this: “MCP over stdio is probably not needed and adds complexity over writing a simple CLI. But MCP over streamable HTTP? This is an absolute game changer.”
Two things complicate the comfortable version of that story.
First, remote protects the machine, not the data. The MCP exploit that actually materialised, Invariant Labs’ GitHub MCP leak, needed no local execution at all: the agent read a malicious issue through one tool and wrote private repository data out through another. Invariant called it “a fundamental architectural issue” of the agent system, not a bug in the server. A chat tab with a ticketing connector and a wiki connector has that shape by default; Anthropic’s own documentation says connectors “may include hidden instructions.” What governs that isn’t remoteness but the curated list, tool-level blocks and OAuth scope — so in the chat harness the list matters more, not less.
Second, the safe state isn’t the default state. The desktop extension allowlist is off until an owner turns it on — “users will be able to access all desktop extensions in the registry until you enable the allowlist” — and local servers are enabled by default. An ungoverned chat tab does have a local-execution door; closing it is a policy key someone has to set.
The coding tab is a different harness. It has a shell, so it honours the managed MCP file, the allowlists, the sandbox and the kill switches, and that’s the knob you turn for how regulated you need to be — with one gap worth knowing: the connectors the desktop app delivers into a coding session arrive in-process, and “no MCP setting or managed-mcp.json reaches them”; they’re governed from the organization console instead. Anthropic’s CISO guide makes the underlying point: coding agents have “more degrees of freedom and so are more risky, if not governed well.” A shell isn’t the ungoverned option. It’s the one where the control point moves from which servers to what the sandbox and egress let bash reach.
The Efficiency Argument, Checked
The other reason people give for retiring local servers is efficiency, and the canonical example is Playwright. Microsoft’s own MCP README now tells coding-agent users they “might benefit from using the CLI+SKILLS instead,” because “CLI invocations are more token-efficient.” A number travels with that claim: about 114,000 tokens with the MCP server against 27,000 with the CLI.
I tried to find where that number comes from. It has no primary source: the earliest pages attribute it to “the Playwright team’s benchmarks” without a link, and later pages cite each other. Microsoft’s docs publish a decision table — token cost “Lower” for the CLI, “Higher” for MCP — and no multiplier. The two independent head-to-heads I found on current versions measured the same workflow at 16% of the context window with the CLI against 18% with MCP, and, on an identical login-to-dashboard flow, “within ~1%” — because both now return a short path to an on-disk snapshot instead of the page’s accessibility tree. The big gap, where it was real, was an old server version pushing that tree into context: a server-design problem, since fixed.
The better-designed study is Arize’s, 500 trials of GitHub tasks across four difficulty tiers, the official MCP server against two skills driving the gh CLI. Correctness was flat across every arm and “100% across the board” on the two easier tiers. The famous result — MCP costing more than six times as much and taking five times as long — is the hardest tier only, where MCP made “about twelve tool calls per task” against five, because a fixed API can’t pipe intermediate results: “Bash is Turing complete.” That’s the part of the gap I think is structural — composability, on multi-step tasks, for a frontier model driving a tool it has seen a million times in training.
The other part, tool definitions bloating the context, has been engineered away: Anthropic’s deferred tool loading took one setup from about 77,000 tokens of definitions to about 8,700, and accuracy went up, from 49% to 74% on one model, and Claude Code turns that search on by default. And the argument cuts the other way for weaker models: Simon Willison, coming back to MCP in July, notes its tools are “simple enough that smaller models that run on a laptop can still drive them reasonably well,” where a shell “requires a strong model.”
So my read: efficiency is the weakest reason to demote local MCP. On simple tasks with current servers the difference is noise; on complex tasks a CLI wins because of pipes, not because of the protocol. If someone’s argument for killing MCP is a token count, ask for the source. If it’s governance or harness, listen.
What’s Left for Local
Mostly, a wrapper. An empirical study of 116 official servers found 92% implement their tools as bare API wrappers; my image server was one. Where the agent has a shell, the wrapper buys nothing a script doesn’t.
The exception is real, and Playwright’s README names it: MCP “remains relevant for specialized agentic loops that benefit from persistent state.” A live browser session, a debugger attached to a process, an open IDE — state that is the point, in a resource that exists only on that machine. Armin Ronacher, no friend of the protocol, conceded the same: “What is stateful out of the box, however, is MCP.” The developers’ tool brushes against this — building the syntax tree is slow — but legacy code barely changes, so the index can be built weekly, cached on disk and queried by a script that starts in milliseconds. State you can serialize isn’t the exception. State you can’t is.
Where a local MCP server should go
The third branch is where the conversation with the developers landed. Hosting their tool centrally would work, but they improve it weekly, and a hosted server means a pull request, reviewers and a deployment for every improvement; asking a tool that changes every week to live behind a change process is how you stop it changing. So: a script in a skill now, and an open invitation to promote it once it settles — at which point everyone gets it, including the people with no shell.
That’s the framing I’d offer instead of “dead.” A local MCP server is a development stage that gets mistaken for a deployment model. It graduates up, to a remote server with an owner, or sideways, to a script. Very few things have a good reason to stay.
What Would Change My Mind
“Dead” is false as a description: one security vendor’s telemetry has 86% of MCP deployments running locally, and half the official registry is local-install only. My claim is about what I’ll vouch for, not what people run.
And my objection is a missing mechanism, not locality. If the allowlist could say this server, this publisher, this hash, and refuse to start anything else, I’d put the developers’ tool on the list the same afternoon. That exists at the edges — Docker’s MCP gateway can verify image signatures, Windows’ contained MCP servers must carry a package identity — and not yet in the agent clients’ policy files. The day it does, a good part of this post expires.
Final Thoughts
The developers told me they understand the argument; I don’t think they’re fully convinced, and from inside a shell I see why. Blocking a jar while permitting the same code as a script looks like theater from there. It only differs from where I sit: one is something a colleague chose to run, the other is something I told a whole company was safe without asking them.
Three things to take, if you govern agents. Know whether a rule is containment or endorsement, because they need different justifications and you’ll be asked for the wrong one. Know which harness you’re governing — a chat tab with connectors, a coding tab with a shell — because the same server is the safest option in one and the wrong option in the other. And when someone hands you a token count as the reason, ask for the source; when they hand you a local server, don’t ask whether it’s safe, ask which direction it should graduate.
As for my own server: it rotted for months in a checked-in config, enabled by default, and I found out because I needed it on a Monday. A remote server with monitoring would have paged someone. A script would have printed an error. Only the local server could fail in complete silence — which might be the whole argument.
...olds; what changed is my view of local MCP servers as the way to do it. The longer argument is in Are Local MCP Servers Dead?. The rest of this post is left as written.
...tember 2026: that server has since been replaced by a small script called from the same skill — see Are Local MCP Servers Dead?.)*