← Back to essays

CLIs and MCP Belong in the Same Toolbox

·7 min read·By Ry Walker

Correction, September 16, 2026: An earlier version asserted that MCP necessarily loads every tool into context and included a first-person comparison of twenty cents versus a penny per call. No verified measurement supported that comparison. It has been removed, and the argument below distinguishes interface choices from implementation costs.

I want agents to reuse good software. If a task is already a clear command, I would rather start there than build another integration layer just to give it an AI-shaped name. A useful CLI, a short usage guide, and a reproducible script can be an excellent interface.

That is a case for keeping CLIs. It does not establish a case for abandoning MCP. The useful question is which path gives this agent the right capability, with understandable permissions, predictable output, and a manageable failure mode. Sometimes that is a CLI. Sometimes it is an MCP tool. Sometimes a script calls MCP tools and returns a small result.

Separate the protocol from the context strategy

MCP is not synonymous with a remote web service. With stdio, the client starts a server subprocess and exchanges JSON-RPC messages through its standard streams. With Streamable HTTP, requests travel to an HTTP endpoint. A local MCP server can still call an external API, just as a locally installed CLI can. “Local process” and “local data processing only” are different properties.[1][2]

The same distinction applies to discovery. MCP defines tools/list and tools/call, along with tool descriptions and argument schemas. Discovering that catalog does not imply that the host must paste every definition into the model's prompt.[3] The current client guidance explicitly describes progressive discovery: retain the catalog outside model context, expose a lightweight search interface, and load selected definitions when needed. A small catalog may not justify that extra machinery.[4] This is part of the context-engineering problem: deciding which information the agent needs for its next decision.

Anthropic's November 4, 2025 article describes another option: present MCP tools as callable code, let the agent compose operations in an execution environment, and return selected results. Large intermediate values can move between tools without being copied through the model at every step. This still uses MCP.[5]

That architecture has costs too. Generated code needs an appropriately restricted runtime, resource limits, and monitoring. Anthropic explicitly identifies that operational burden; code execution is an implementation choice, not a free optimization that every MCP client already provides.[5]

Where I would start with a CLI

For repository work, I would first look for an existing command that the team already understands. Shell pipelines connect one program's output to another's input, making it possible to combine established tools without asking a model to shuttle each intermediate value. Failure handling still matters: Bash normally reports the last command's status, while pipefail can surface an earlier pipeline failure.[6]

A concrete read-only example is GitHub CLI. It can request selected PR fields and filter its JSON output with an embedded jq expression; a separate jq installation is not required for that option.[7][8] For a repository you are authorized to inspect:

gh pr list --repo OWNER/REPO --state open --limit 100 \
  --json number,title,isDraft \
  --jq 'map(select(.isDraft == false) | {number, title})'

This retrieves up to 100 open PRs and returns only numbers and titles for the non-draft entries in that batch. It is not a complete-inventory guarantee for larger repositories. The example illustrates output selection, not a measured cost advantage over an MCP implementation.[7][8]

My checklist for an agent-friendly CLI is straightforward: clear subcommand help, stable machine-readable output, useful exit codes, noninteractive authentication, and tests for the actual operations. A skill can explain when to use it and which workflow to follow. Those instructions do not replace executable permissions or make an unreliable command reliable.

Nor is terminal access free of friction. The runtime must have the right binary, version, credentials, and working directory. A shell gives the agent considerable expressive power; the execution policy needs to match that power. These are reasons to design the environment deliberately, not reasons to discard command-line tools.

What MCP adds

MCP gives clients and servers a shared way to advertise and invoke capabilities. Input schemas describe accepted arguments; optional output schemas describe structured results. A host can build its integration around that contract instead of maintaining a separate command parser for each service.[3] That is valuable when several applications need the same integration, or when the client does not provide a general shell.

For protected HTTP servers, MCP also specifies an authorization framework based on OAuth: discovering authorization services, requesting scoped access, and validating that tokens target the intended resource. Authorization is optional at the protocol level, and the HTTP framework is not the stdio credential model. A deployment still has to implement and configure it correctly.[9]

CLIs can offer browser login and scoped service credentials too. GitHub CLI, for example, documents a browser flow, system credential storage with a plaintext fallback when unavailable, and environment-token support for automation.[10] The distinction is not “MCP has authentication; CLI does not.” It is how each application acquires, stores, scopes, and uses credentials.

I would also retire the claim that an MCP integration necessarily requires building a separate API first. Tools can expose computations as well as external API calls.[3] If a CLI and MCP server wrap the same operation, my preference is a tested implementation underneath two thin interfaces. The shared behavior deserves tests; each adapter also needs tests for its own errors, inputs, and authorization boundary.

MCP is testable from a shell. Its Inspector provides a CLI that can list and call tools, inspect JSON results, and return exit codes for CI checks.[11] A protocol adapter adds work, but “CLIs are testable and MCP is not” is the wrong comparison.

Measure the workflow that actually runs

There is no protocol-wide twenty-to-one price ratio here. I would compare the same task against the same underlying service and record:

  • Model work: discovery text, schemas actually loaded, intermediate results, output tokens, and extra reasoning or retry turns.
  • Execution work: process startup, server/network round trips, pagination, filtering, and time spent waiting for the underlying service.
  • The result: correctness, completeness, retries, and whether both routes enforce equivalent access and approval requirements.
  • The bill: model, API, compute, and integration-provider charges, with cached and uncached runs distinguished where relevant.

This is an evaluation plan, not a benchmark performed for this essay. A terse CLI response can avoid unnecessary context; an MCP host using selective discovery and code execution can pursue the same goal. Conversely, either path can return too much data or send the agent through repeated failed attempts. Compare those implementations before attributing the outcome to the interface.[8][4]

Tembo is a concrete example of using both

Disclosure: I am Tembo's co-founder and CEO.

Tembo runs coding agents with repository tools and dependencies in cloud or self-hosted environments.[12] Its documented sandbox interface includes a tembo CLI for tasks such as previews, uploads, and pull requests, alongside MCP tooling for connected services. The MCP path includes search_mcp_tools, get_mcp_tool_details, and execute_mcp_code, which is documented to compose calls in TypeScript without putting intermediate results into agent context.[13]

That is a useful design example for this argument: terminal operations and structured service access can coexist. Tembo's connection guide also distinguishes personal from shared custom servers and supports OAuth-based remote connections. Availability depends on the session and configuration; a remote service still receives requests when Tembo is self-hosted.[14] These are documented capabilities, not evidence that Tembo is universally faster, cheaper, or compatible with every server.

My default is to reuse a good CLI when it fits the task, and to use MCP where its discovery and integration contract remove work. Keep deterministic filtering outside the model when practical. Make permissions explicit. Test the failure paths. Optimize the measured workflow, and keep both interfaces available when they earn their place.

Key takeaways

  • MCP can run locally, and discovering tools does not require loading every schema into the model's context.
  • Reuse a good CLI for shell workflows; choose MCP when structured discovery and interoperable access help the application.
  • Progressive discovery and code execution can reduce context overhead while continuing to use MCP.
  • Compare complete workflows, credentials, and failure handling instead of assuming either interface is always faster or cheaper.

FAQ

Is a CLI always cheaper or faster than MCP?

No. Compare the actual call path, model turns, discovery strategy, returned data, and service charges for the same task; neither interface guarantees lower end-to-end cost or latency.

Does MCP load every tool into the model's context?

No. A host can discover tools without exposing every definition to the model, then select relevant schemas on demand. Programmatic tool calling can also keep intermediate results outside model context.

Can MCP run locally?

Yes. Its stdio transport lets a client launch a local server subprocess and communicate through standard input and output. The server may still call remote services.

When should an agent use a CLI instead?

A CLI is a useful default when the execution environment already has a reliable command, authentication, and suitable output formats. MCP can complement it when an application needs discoverable, structured tool access.