Skip to content
verify mcp Beta VerifyMCP is currently in beta. If you notice any issues, get in touch and we’ll put it right.

MCP vs CLI: which should your coding agent use, and when?

By Stuart · 4 Aug 2026 · 10 min read
MCP vs CLI: which should your coding agent use, and when?, VerifyMCP

If your coding agent already has a shell in an environment you trust, a well documented CLI is usually the cheaper and more reliable way to give it a capability. An MCP server earns its place when the agent has no shell, when the capability lives with a remote third party, or when you want a tool surface you can enumerate and audit before anything runs. The two options spend context differently, fail differently, and carry different security assumptions, and most of the online argument comes from looking at only one of those three axes.

We score every server in the official MCP registry, which means we read a lot of tool schemas, so we have a view on the part of this debate that rarely gets airtime: what each choice does to your ability to know what an agent can reach.

What is actually different between a CLI and an MCP server?

A CLI is a program the agent runs through its shell tool. The model writes a command line, the harness executes it in a subprocess, and the model reads whatever came back on stdout. An MCP server is a separate process (local or remote) that advertises typed tools over JSON-RPC; the client fetches the tool list, puts the definitions into the model’s context, and the model invokes tools as structured calls rather than text commands.

CLI + shellMCP server
How the agent discovers itTraining data, --help, docs read on demandtools/list returns declared tools with schemas
Context cost before first useClose to zeroTool definitions loaded into context, in most clients on every request
Result formatstdout text the model parsesTyped content, optionally structuredContent validated against an outputSchema
ComposabilityPipes, files, exit codes, no model round trip between stepsOne model round trip per tool call
Works without a shellNoYes
State between stepsFiles on diskExplicit handles passed back as arguments (the protocol itself is stateless)
Declared attack surfaceNone; the surface is everything the shell can reachEnumerable, diffable between versions, scoreable
Third-party operator in the loopNo (for local tools)Yes, for remote servers

Neither column wins outright. The rest of this post is about when each row dominates.

Why does MCP cost more context than a CLI?

This is the CLI camp’s strongest point, and it is correct. Anthropic’s own engineering write-up on code execution with MCP states it plainly: most MCP clients load all tool definitions upfront into context, and agents connected to many servers can burn through enormous amounts of tokens before reading a single request. Their worked example (a two-step Google Drive to Salesforce task) dropped from 150,000 tokens to 2,000 when the agent called the tools from code instead of holding every definition and intermediate result in context.

A CLI sidesteps the whole problem. The model already knows git, gh, grep and curl from training; the “tool definition” for a shell is one generic Bash tool, and everything else is recalled or read on demand from --help. Armin Ronacher’s argument for code over MCP adds the second half: MCP composition happens through inference, one model round trip per call, while shell commands compose through pipes and scripts with no model in the middle. Run the same GitHub task through the GitHub MCP server and then through the gh CLI and the CLI almost always uses context more efficiently. He is right about that, and pretending otherwise does MCP no favours.

The current MCP specification is aware of the cost. The 2026-07-28 revision made the protocol stateless and added result caching, and the tools page now tells servers to return tools in deterministic order specifically so that clients can cache the list and keep LLM prompt-cache hit rates up. That mitigates the per-request bill; it does not remove the upfront one. A server with thirty verbose tools still occupies context that a coding agent would rather spend on your code.

What does Playwright’s own tooling tell us?

Browser automation is where this debate stopped being theoretical, because Microsoft’s Playwright team now ships both options and positions them honestly. Playwright MCP exposes browser control as MCP tools and streams page snapshots back through the protocol. The newer Playwright CLI targets coding agents directly: each action is a shell command, page snapshots are written to disk as files, and the agent reads a snapshot only when it decides it needs one. The repository’s own positioning is that CLI invocations avoid loading large tool schemas and verbose accessibility trees into model context, while the MCP server remains the right fit for clients that keep persistent state and cannot run commands.

Independent numbers back the direction, with spread. One benchmark of a roughly ten-step login-and-form task measured about 114,000 tokens through Playwright MCP against about 27,000 through the CLI. Better Stack’s head-to-head on a shorter task found a much smaller gap: 31k for the CLI against 35k for the MCP server, with most of the MCP overhead being the ~3,600-token schema load against a 68-token CLI description. The MCP run also failed the screenshot verification step the CLI run completed, which the token totals alone do not show. Treat the exact multiples as workload-dependent. The consistent findings are that the MCP schema costs you before the first click, and that returning full accessibility trees through the model costs you on every step, where the CLI’s write-to-disk pattern lets the agent skip what it does not need.

If you searched “playwright mcp vs cli”, that is the answer: in a coding agent with a shell, use the CLI; keep the MCP server for clients that have no shell to offer.

What do you give up by dropping MCP?

Three things, and for some workloads they are decisive.

  • Discoverability without guesswork. tools/list returns the actual tool surface with a JSON Schema per tool. The model does not need the tool in its training data, does not hallucinate flags that were removed two versions ago, and a schema change shows up as a changed schema rather than a subtly different stdout format that silently breaks your parsing.
  • Typed results. MCP tools can declare an outputSchema and return structuredContent that the client validates against it. Parsing stdout works until the tool ships a new banner, a warning line, or localised output. A validated structure fails loudly instead.
  • Clients that have no shell. Claude Desktop, ChatGPT connectors, chat products and most non-developer surfaces cannot hand the model a terminal, and should not. For those hosts, MCP is not the expensive option; it is the only option. The same goes for reaching a remote service that was never going to run on your machine, where MCP’s per-request OAuth model gives you scoped credentials instead of an API key exported into a shell environment every subprocess inherits.

There is also an operational argument the CLI camp underweights: a CLI must be installed, version-matched and on PATH on every machine the agent runs on. A remote MCP server is maintained once and every connected agent gets the same behaviour.

Which one is safer to hand to an agent?

Here is the asymmetry that the token-count debate misses, and it cuts both ways.

Giving an agent a shell grants it everything the shell can reach: every binary on PATH, every credential in the environment, the filesystem, and outbound network. There is no declared surface. You cannot enumerate in advance what “Bash” might do, you can only audit transcripts after the fact, and a prompt-injected agent with a shell has the whole machine as its blast radius. That is the price of the flexibility that makes CLIs so cheap in tokens.

An MCP server, by contrast, has a declared tool surface. tools/list is a machine-readable statement of what the server offers, which means you can enumerate it before connecting, diff it between versions to catch a quietly added tool, and score it. That is precisely what VerifyMCP does: our engine connects to every server in the official registry, reads the schemas, probes transport and authentication, and publishes an independent score. As of 18 August 2026, that is 23,066 servers exposing 25,124 components. You cannot do any of that to “a shell”.

But a declared surface is not the same as a safe one, and MCP adds something a local CLI does not have: an operator. 12,682 of those components are remote, meaning a third party runs the process, sees every argument your agent sends, and can change what the tools do without you shipping anything. Only 1,487 of 12,682 remote components declare a required secret header in their registry entry, though that undercounts the ones demanding OAuth without declaring a header. The spec itself instructs clients to treat tool descriptions and annotations as untrusted unless the server is trusted, because descriptions are injected into your model’s context and are a known prompt-injection channel. Our threat model covers this in detail.

So the honest comparison is not “which is safer” but which risks you are choosing:

  • A local CLI has no third-party operator, but an undeclared surface. Your controls are sandboxing, allowlists and after-the-fact audit. Supply chain still applies; npm install -g is not a trust ceremony.
  • An MCP server has a smaller, declared, auditable surface, but adds a dependency and (if remote) an operator who is now inside your agent’s loop.

Neither is automatically the secure choice. A vetted MCP server with three read-only tools is a far smaller grant than a shell; an unauthenticated remote server from an unknown operator is a far larger one than a pinned, locally installed CLI.

When should you use a CLI, an MCP server, or both?

Use a CLI when:

  • the agent runs with a shell in an environment you already trust with that shell (Claude Code, Cursor, CI runners you control);
  • the tool is something models know from training, such as git, gh, docker or kubectl;
  • the workload is high-volume or context-constrained, where per-task token cost compounds;
  • intermediate output is large and better written to disk than pushed through the model, the pattern Playwright CLI made standard.

Use an MCP server when:

  • the client has no shell, or you do not want to grant one; a declared three-tool surface is a smaller thing to hand an agent than a terminal;
  • the capability is a remote third-party service where per-request OAuth beats long-lived keys in environment variables;
  • you need typed, schema-validated results rather than parsed stdout;
  • several agents or non-developer users need the same capability with centralised authorisation and audit.

Use both when the same capability serves both worlds. Playwright is the template: the CLI for coding agents that have a filesystem and a shell, the MCP server for sandboxed clients that do not. If you maintain a developer tool, shipping a thin MCP wrapper around the same core as your CLI costs little and lets each host pick the surface that suits it.

The runtime usually decides for you. Where it does not, default to the CLI for trusted local work and make MCP earn its context cost with discoverability, typing, or reach you could not get otherwise.

Vet the option you choose

Whichever way you go, the vetting step is the part that does not change. If you adopt a CLI, pin its version and sandbox the shell that runs it. If you adopt an MCP server, its declared surface means it can be checked before you connect: browse the registry, open the server you are considering, and read its score, its tool list and its transport findings. Our scores are independent estimates, not guarantees, and anything we cannot verify is marked inconclusive rather than guessed, but an enumerated surface with a published score beats an unread one every time. How we score explains exactly what goes into the number.