CLI vs MCP: Should Your Agent Call Tools or Run Commands?

Cover Image for CLI vs MCP: Should Your Agent Call Tools or Run Commands?
James Okafor
James Okafor

Why the CLI vs MCP debate exists

Sometime in mid-2025, a handful of engineers who spend their days building coding agents started noticing something: the agent already had a working shell. It already knew git, gh, curl, jq, docker, and a hundred other command-line tools from training. So why were they also wiring up an MCP server, with its JSON-RPC handshake and a wall of tool schemas, just to do the same job a one-line shell command could do?

That question is the heart of the CLI vs MCP debate, and it picked up real momentum after benchmarking write-ups like Mario Zechner's MCP vs CLI: Benchmarking Tools for Coding Agents and a wave of follow-on posts arguing that command-line tools are simply more token-efficient for autonomous coding agents than MCP's tool-calling model. The debate isn't really about whether MCP "works" — it clearly does, and it has become the de facto standard for connecting AI applications to external systems, per the official MCP documentation. It's about where MCP's overhead is worth paying, and where a trusted agent with shell access should just run the command.

Two forces collide here. First, MCP works by having a client and server exchange tool definitions (name, description, JSON Schema for parameters) over a transport, and the host application loads those definitions into the model's context before any tool is even called. Second, agentic coding tools like Claude Code, Codex CLI, and Cursor's agent mode increasingly run inside a real shell, sandboxed but capable of executing arbitrary commands. Once an agent can run gh pr create directly, adding an MCP server that wraps the GitHub API starts to look like a detour — extra schema, extra round trips, extra tokens, for output the agent could have gotten from a command it already knows by heart.

The case for CLI: less ceremony, more tokens for reasoning

Schema overhead is real and it's often large

The core technical complaint is token overhead. MCP hosts typically load every tool's name, description, and full JSON Schema into context up front, before the agent decides it needs any of them. For a small server this is trivial. For a large one it isn't: writeups comparing the two approaches cite examples where a fully-loaded GitHub MCP server's tool definitions run into the tens of thousands of tokens, consumed before a single question gets answered — see the numbers collected in MCP vs CLI for AI Agents: Which One Should You Use in 2026? and MCP vs CLI for AI Agents: When to Use Each and Why It Matters for Token Costs. A CLI invocation, by contrast, costs roughly what its command string costs — a few dozen to a couple hundred tokens — because the agent already knows the tool's interface from pretraining and doesn't need it re-described in context.

That gap compounds. Every tool definition sitting in the system prompt competes with the actual reasoning the model needs to do, and it's paid on every single turn of a long agentic session, not just once. For an agent making hundreds of tool calls over a multi-hour coding session, shaving tens of thousands of tokens off the fixed overhead is not a rounding error.

Composability and familiarity

CLIs also compose the way Unix tools have always composed: pipes, redirection, grep, jq, xargs. An agent that can run git log --oneline | grep fix | wc -l gets a precise answer in one shell call, chaining well-understood primitives. MCP tool calls, by contrast, are individual request/response round trips — there's no native equivalent of a pipe between two MCP tools without the model manually shuttling data through its own context.

And because command-line tools like git, docker, kubectl, and curl are extensively represented in training data, models tend to already "know" their flags, output formats, and idioms cold. There's no schema to read because the knowledge is baked in. Mario Zechner's benchmark found the two approaches landing close in raw success rate and cost once tool design was controlled for, but the piece is explicit that the deciding factors are portability and the ability to pipe and filter CLI output through other CLI tools, not some inherent MCP defect — see MCP vs CLI: Benchmarking Tools for Coding Agents.

"Bad MCP servers," not bad MCP

It's worth being precise about what the CLI camp is actually criticizing. The sharper versions of this argument, like Zechner's and Jannik Reinhard's CLI Tools vs MCP: Better AI Agents With Less Context, don't claim MCP is broken as a protocol. They claim that a lot of MCP servers in the wild are thin, mechanical wrappers around REST APIs that dump raw, unfiltered JSON into the model's context — the same anti-pattern this blog has covered before in Reducing MCP Token Usage by 100x. A well-designed CLI tends to have terse, composable output by convention; a poorly designed MCP tool often returns everything the underlying API gives it. The comparison that matters is tool design quality, not transport.

The case for MCP: the parts a shell can't give you

The CLI argument is strongest for a specific persona: a single developer, in a trusted local environment, driving a coding agent that already has full shell access. Step outside that persona and the calculus flips fast.

Most AI applications don't have a shell

A shell is a developer tool. ChatGPT's web client, a Slack bot, a customer-support agent, a mobile app — none of these have a terminal to run gh in, and most of their users couldn't operate one if they did. MCP exists precisely so that "GUI clients," hosted assistants, and non-technical end users can reach the same tools and data sources a developer would reach from a terminal, through a protocol the host application controls. That's the use case the MCP documentation leads with: connecting AI applications like Claude or ChatGPT to calendars, databases, and workflows for ordinary end users, not just terminal-native engineers.

Sandboxing, permissions, and blast radius

Handing an agent an unrestricted shell means it can, in principle, do anything the underlying OS user can do: read arbitrary files, make arbitrary network calls, install packages, delete things. MCP servers narrow that surface deliberately — a server exposes a fixed set of named operations with typed parameters, and a host can grant or deny each tool individually, log every call, and keep the agent from improvising rm -rf out of a creative misreading of the task. Our own MCP security best practices post covers this in more depth, but the short version is: a CLI is a general-purpose weapon, and MCP tool definitions are a curated toolbox. For anything touching production data, other people's accounts, or regulated information, that curation is the point, not the overhead.

Interestingly, one of the CLI-favoring benchmarks found the opposite problem in practice: raw shell invocations tripped Claude Code's built-in malicious-command detection on nearly every call, inflating token usage far past the MCP equivalent for the same task — a reminder that an unconstrained shell has its own hidden costs once a host has to police it. See MCP vs CLI: Benchmarking Tools for Coding Agents for the specifics.

Auth, remote services, and no-CLI APIs

Plenty of tools an agent needs simply have no CLI. A niche internal API, a SaaS product without a command-line client, a service that only exposes a GraphQL or REST endpoint — someone still has to write the integration, and MCP gives that integration a standard shape the agent already knows how to consume, instead of a bespoke CLI nobody outside one team has ever seen. MCP also standardizes how auth gets handled — OAuth flows, API keys, session tokens — behind the server boundary, so the model never needs raw credentials in its context or its shell history the way a curl -H "Authorization: Bearer $TOKEN" command would expose them.

Structured results and discoverability

A CLI's output is text meant for a human terminal: column-aligned, sometimes colorized, occasionally inconsistent between subcommands and tool versions. MCP tool results can be structured JSON with a defined schema, which is easier for a model to parse reliably and easier for a host to validate, redact, or post-process before it ever reaches the model. MCP also supports capability discovery — a client can ask a server "what tools do you have" and get machine-readable descriptions back, which matters when an agent is meeting a new integration for the first time and has no prior training exposure to it, unlike git or docker.

CLI vs MCP: a side-by-side comparison

CLI (direct shell) MCP
Token overhead Low — cost of the command string, tool already known from training Higher — full tool schemas typically loaded up front
Best client Terminal-native coding agents (Claude Code, Codex CLI, Cursor agent mode) Any AI application: chat apps, web clients, mobile, hosted assistants
Access control Coarse — whatever the OS user can do Fine-grained — per-tool permissions, host-level gating
Auth handling Manual — credentials often visible in commands/env Standardized — handled behind the server boundary
Works for non-technical users No — requires a shell and CLI literacy Yes — the host app mediates everything
Remote / no-CLI services Requires someone to build a CLI first Native fit — just implement a server
Composability Native pipes, redirection, filtering Round-trip tool calls; composition happens in the model or via code execution
Discoverability Relies on model's training knowledge of the tool Explicit, machine-readable tool listing
Auditability Depends on shell/session logging Structured, per-call logging is a natural fit

The nuanced middle ground

Treating this as a strict either/or misses how the ecosystem is actually converging. A few things are becoming clear:

For trusted, terminal-native coding agents, CLI-first is often the right default. If your agent already runs in a sandboxed shell — Claude Code, Codex CLI, and similar tools all work this way — and the operations are things like git, gh, or your project's own build scripts, going through MCP to wrap a tool the agent already knows how to invoke adds cost without adding safety, since the shell access is already there either way.

For hosted, consumer-facing, or multi-tenant AI applications, MCP is close to non-negotiable. There's no shell to fall back to, permissions need to be scoped per user or per organization, and the same server needs to work identically whether it's called from a chat UI, a mobile app, or another agent. Our getting started with MCP guide walks through building exactly this kind of integration.

MCP's token overhead is a solvable engineering problem, not a permanent tax. Anthropic's own Code execution with MCP: building more efficient AI agents describes treating MCP servers as code APIs that agents explore and call through generated code rather than loading every tool definition into context up front — cutting a worked example from roughly 150,000 tokens down to about 2,000 by having the agent discover tools on demand (e.g., by listing a ./servers/ directory) and keeping intermediate results inside the execution environment instead of round-tripping them through the model's context. That's roughly the same instinct behind dynamic toolsets and gateway-based filtering we covered in Reducing MCP Token Usage by 100x: the fix isn't abandoning MCP, it's stopping the practice of loading every tool schema for every request regardless of relevance.

Tool design usually matters more than protocol choice. Both camps converge on this point from opposite directions. A CLI with bloated, inconsistent output is just as painful for an agent as a badly designed MCP server that dumps raw API responses. A terse, well-documented MCP tool with a tight schema can beat a sprawling CLI with dozens of flags. The protocol is a delivery mechanism; the actual interface design is what determines whether an agent uses it well.

A simple decision framework

Ask these questions, roughly in order:

  1. Does the calling application have a shell at all? If it's a hosted chat product, a mobile app, or anything without a terminal, MCP (or an equivalent tool-calling protocol) is your only real option.
  2. Is the agent already trusted with broad shell access? If yes, and the operation is something a well-known CLI already does well (git, package managers, cloud CLIs), calling it directly is often simpler and cheaper.
  3. Does the operation need scoped permissions, auth handling, or an audit trail per user? If yes, put it behind an MCP server even if a CLI exists, so access is mediated and logged rather than inherited wholesale from the shell.
  4. Is there no CLI for this system at all — a proprietary API, an internal service, a remote SaaS product? Build (or find) an MCP server; that's the case MCP was designed to standardize.
  5. Is token overhead actually the bottleneck, or is it a large tool count loaded eagerly? If the latter, look at dynamic tool discovery or code-execution patterns before ripping MCP out — the overhead is frequently an implementation detail, not an inherent cost of the protocol.

Conclusion

The CLI vs MCP framing is useful for surfacing a real, measurable cost — MCP's default of loading every tool schema up front is expensive, and for a trusted coding agent that already has a shell, running gh or git directly is often just less wasteful. But the debate collapses into a false dichotomy if it stops there. MCP wasn't built to compete with the terminal; it was built for the much larger set of AI applications that never had one — hosted assistants, consumer apps, and multi-tenant systems that need scoped permissions, standardized auth, and structured, auditable results. The realistic answer for most teams building agents today is both: CLI-first for trusted, terminal-native coding agents doing well-known operations, and MCP for anything that needs to reach non-technical users, remote services without a CLI, or governed access — with the token-efficiency gap increasingly closed by smarter tool loading rather than by choosing one protocol and discarding the other.