MCP Servers Are the Wrong Abstraction
For Coding Agents
Every agent platform wants you to write MCP servers now. Anthropic launched the Model Context Protocol in November 2024, and within a year the ecosystem exploded. FastMCP tracks over 1,800 servers as of March 2026, up from 425 in August 2025. OpenAI, Google DeepMind, Microsoft, and AWS all adopted the protocol. The pitch is clean: one standard way for AI agents to discover and use tools.
Here's the thing nobody seems to want to say: if your coding agent already has shell access, most MCP servers are dead weight.
I've been using AI coding agents since Codex and Claude Code were first released. I've built MCP servers. I've integrated them into my workflows. And for agentic coding specifically, where the agent can already execute commands on the host, CLIs beat MCP almost every time. MCP has its place, but that place isn't "wrapping tools your agent can already call directly."
What MCP Actually Is
MCP uses JSON-RPC over stdio or HTTP to let an agent discover tools, call them with typed inputs, and get structured responses back. Servers can also expose resources (files, data) and prompts (templates), and there's a sampling mechanism that lets servers request LLM completions from the client. The capability negotiation at connection time means both sides agree on what's supported before anything happens.
On paper, this is thoughtful protocol design. And for agents that don't have access to a shell, it solves a real problem: how does the agent interact with the outside world? But if your agent already has a command tool, most MCP servers in the wild just wrap a REST API or a CLI you already have installed.
The Wrapper Problem
Bloomberry analyzed 1,400 MCP servers and the pattern is obvious. A huge chunk of the ecosystem is thin wrappers around existing tools. There's an MCP server for GitHub, but gh already exists. There's one for Kubernetes, but kubectl already exists. There's one for Docker, but you get the idea.
Jeremiah Lowin makes a good case in "Stop Converting Your REST APIs to MCP" that the problem isn't MCP itself. It's blindly converting an API's full surface area into MCP tools. His argument is that you should design MCP servers around what a specific agent needs to accomplish, not mirror every endpoint your API exposes. A refund agent doesn't need your entire platform API. It needs a handful of purpose-built tools scoped to its job. That's good advice for operational agents, and it ties into the multi-agent architecture I'll get to later. But for coding agents, the question is different. If your agent can already call gh, why build a purpose-scoped MCP server around GitHub's API at all?
The argument for MCP wrappers is usually "but then any MCP-compatible client can use them." Which is true, and that matters for agents running in sandboxed environments without shell access. But coding agents like Claude Code, Cursor, and Windsurf already have subprocess execution. If your agent can run a command, the subprocess approach doesn't require a running server process, a JSON-RPC transport layer, or capability negotiation for something as simple as "list my open PRs."
Context Is the Real Cost
This is where it gets expensive. Simon Willison pointed out that the GitHub MCP server alone consumes roughly 55,000 tokens just to describe its 93 tools. By comparison, gh --help is 2,550 characters, roughly 638 tokens. That's a 86:1 ratio for the same integration.
And CLIs have a built-in solution for complexity that MCP had to bolt on after the fact. CLI help is progressively disclosed. gh --help lists the subcommands and what they do. gh pr --help drills into pull request operations. gh pr list --help gives you the flags for that specific command. The agent only loads the context it needs for the operation it's about to perform. This is the same pattern we use with skill frontmatter in coding agents: give the agent a summary up front and let it drill deeper when it needs to.
When your agent has a 200k token window and you're burning 55,000 tokens on tool descriptions for a single integration, you've given up a quarter of your context before the agent reads a single line of your code. Stack a few MCP servers together and you're out of room. Jannik Reinhard's benchmarks showed CLI-based agents achieving 28% higher task completion rates with what he calls a Token Efficiency Score of 202 vs 152 for MCP.
Anthropic introduced a tool search capability in late 2025 to address this, letting agents dynamically discover tools instead of loading all definitions upfront. Their own testing showed 50+ MCP tools consuming ~72K tokens reduced to ~8.7K with tool search enabled. That's a 95% reduction, and Willison changed his position after that. Fair enough. But the fact that "don't load all tools into context at once" needed a purpose-built feature tells you something about the abstraction. CLIs solved this decades ago with --help and man pages.
Unix Already Solved This
Every agent I use can shell out to a command and read its stdout. That's the interface. It's the same interface that's been composing tools since the 1970s.
gh pr list --json number,title,state | jq '.[] | select(.state == "OPEN")'
That's typed output. It's composable. It uses exit codes for error handling. It works with pipes. My agent can read the man page or --help output to figure out the flags. These tools were designed for exactly this kind of interaction: a caller that reads structured text and makes decisions based on it.
MCP tools, by contrast, are isolated. You call one tool, get a response, then call another. There's no native piping. The mcpblox project exists specifically to bolt Unix-style composition onto MCP, which tells you that the protocol didn't account for it.
I run gh, kubectl, jq, curl, git, and standard Unix tools with my agents every day. They work. The agent already knows how to use them because they appear heavily in training data. There's no installation, no configuration, no server process to manage.
The Security Story Is Worse, Not Better
One of the selling points for MCP is structured permission scoping. The idea is that MCP servers declare their capabilities and clients can restrict access. For agents without shell access, this is the security model. You control what the agent can do by controlling which MCP servers it connects to. That's reasonable.
But for coding agents that already have shell access, adding MCP servers doesn't improve your security posture. It widens it. Now you have the shell attack surface plus the MCP attack surface. And the MCP security record isn't great. BlueRock analyzed 7,000+ MCP servers and found 36.7% have potential SSRF vulnerabilities. That includes Microsoft's own MarkItDown server, where an attacker could use the convert_to_markdown tool to access arbitrary URIs, including AWS instance metadata endpoints. Anthropic's official Git MCP server had a path validation bypass (CVE-2025-68145) where repository path restrictions weren't enforced.
The CLI security model isn't perfect either, but it's been battle-tested for decades. File permissions, PATH management, sandboxing with containers or nsjail. We know how to restrict what a subprocess can do. MCP server sandboxing is still an open question.
And then there's the supply chain angle. When you install an MCP server, you're running someone else's code with access to your agent's context and potentially your file system. There's no package signing standard, no SBOM requirement, no equivalent of npm audit. BlueRock launched a trust registry to start addressing this, but the fact that it needed to be built from scratch in 2026 tells you how young the ecosystem is.
When MCP Actually Makes Sense
I keep framing this as "coding agents with shell access" for a reason. Take away the shell, and the calculus flips completely.
Consider a customer service platform where agents handle refunds, shipping, and inventory. Each agent only needs access to its own set of tools. The refund agent doesn't need the shipping API. The inventory agent doesn't need the payment processor. MCP lets you scope each agent to exactly the tools it requires, and because each agent has a narrow focus, the context overhead problem mostly disappears. You're not loading 93 GitHub tools into an agent that just processes returns.
This is where MCP's architecture actually shines. Non-coding agents in sandboxed environments, broken into specific responsibilities, each with a curated set of MCP tools. The protocol was designed for exactly this kind of structured, permission-scoped interaction.
The common rebuttal is that MCP also helps coding agents with stateful connections. Persistent database sessions, WebSocket streams, long-lived service connections. But think about when a coding agent actually needs those. If my agent needs to query Postgres, psql -c "SELECT ..." --csv opens a connection, runs the query, and exits. The connection lifecycle is handled by the CLI. I don't need a persistent database connection for that. Where persistent connections matter is something like Postgres LISTEN/NOTIFY, where an agent monitors a database for real-time changes. But that's an operational agent use case, not a coding one.
WebSocket streams are the same story. I don't want my coding agent writing code based on messages arriving from a live WebSocket feed. That's a security concern, not a feature. If the agent needs data from a WebSocket-based service, a CLI that connects, grabs what it needs, and disconnects is the safer pattern.
Resource subscriptions and sampling are the two MCP features that hold up under scrutiny. Subscriptions let a client watch for resource changes, which is useful for operational monitoring. Sampling lets the MCP server request LLM completions from the client, enabling recursive agent patterns where the tool itself can think. Neither has a CLI equivalent. But neither is a coding agent use case.
The problem isn't MCP existing. It's the ecosystem pressure to bolt MCP onto coding agents that already have a perfectly good way to call the underlying tool directly.
My Workflow
Here's what I actually use day to day. My coding agents shell out to gh for GitHub operations, glab for Gitlab operations, kubectl for cluster work, jq for JSON manipulation, and git for everything version control. For beads (my issue tracker), it's a Golang CLI that my agent calls directly. For Slack and web search, I use MCP because there's no good CLI equivalent for those integrations, and authentication is handled by the MCP server's OAuth flow.
The split isn't ideological. It's practical. If a CLI exists for the tool, use the CLI. If there's no CLI and the agent can't just curl the API, that's where MCP earns its place.
The Zuplo blog frames this as "when does each make sense," which is the right question. But that's not the message developers are hearing. They're hearing "build an MCP server" because that's what every agent platform is pushing, even when the agent sitting on the other end has a perfectly functional shell.
The Microservices Parallel
We've seen this pattern before. In 2015, the industry took function calls and turned them into network hops because the architecture diagram looked better. We spent the next decade learning that most things that work as a library call don't benefit from being a microservice.
MCP is doing the same thing to tool invocation for coding agents. Taking something that works as a subprocess call and adding a protocol layer, a transport mechanism, a capability negotiation handshake, and a running server process. For agents without shell access, that overhead buys you the ability to interact with external tools at all. For coding agents that can already run commands, it buys you nothing but complexity.
The mental model is simple. No shell? MCP is your interface to the world, and you should architect your agents around scoped, purpose-specific tool access. Shell available? Start with CLIs and reach for MCP only when no CLI exists for what you need.
The ecosystem will sort itself out. The wrapper servers will get abandoned or replaced by coding agents that just call the underlying CLIs directly. The MCP servers that survive will be the ones powering non-coding agents with scoped, sandboxed tool access. And the handful of MCP integrations that coding agents actually benefit from will be the ones where no CLI alternative exists.
Until then, if your coding agent can run a command, let it.
Here's a challenge. Pick one MCP server in your coding agent's config that wraps a CLI you already have installed. Remove it. Let the agent use the CLI directly for a week. If you notice a difference, add it back. My bet is you won't.