Oct 7, 2026

Engineering

Why I Build CLIs for Coding Agents, Not MCP Servers

Read time: 6 min read

Why I Build CLIs for Coding Agents, Not MCP Servers

Key Takeaways

Connect an MCP server to a coding agent and it reads every tool definition on that server before you type a word. Five common servers take about 55,000 tokens. A crowded context makes models pick the wrong tool more often and get less reliable overall. A command-line tool costs nothing until it runs, so that is what I build.

open sourceCLIcoding agentsMCPcontext windownotion-cli

The short version

I run most of my own work through coding agents, and an agent is only as useful as the tools it can call. Most of the services I depend on (Notion, Inngest, Xero, Outlook) have good APIs and poor terminal clients, so I built my own. I built them as command-line tools rather than MCP servers on purpose.

When you connect an MCP server to a coding agent, the agent reads the name, description and full parameter schema of every tool on that server before you have typed anything. Connect a few servers and tens of thousands of tokens are spent before the conversation starts.

That is space the model cannot use for your actual problem. The research is fairly clear that a crowded context makes models worse at the job: more likely to pick the wrong tool, more likely to miss what matters, slower and more expensive on every turn.

A command-line tool costs nothing until the agent runs it.

What an MCP server puts in the context window

Most MCP clients load every tool definition from every connected server into the context window up front. Anthropic published what that looks like for a fairly ordinary five-server setup in their advanced tool use post:

  • GitHub: 35 tools, about 26,000 tokens
  • Slack: 11 tools, about 21,000 tokens
  • Sentry: 5 tools, about 3,000 tokens
  • Grafana: 5 tools, about 3,000 tokens
  • Splunk: 2 tools, about 2,000 tokens

That is 58 tools and roughly 55,000 tokens, in Anthropic's words, "before the conversation even starts". Jira alone adds about 17,000 more. They also report seeing tool definitions take 134,000 tokens inside Anthropic before they optimised it.

Those definitions sit there on every turn, whether the task touches GitHub or not.

Why a crowded context makes the agent worse

It picks the wrong tool more often

Anthropic's own documentation says Claude's ability to pick the right tool degrades once you exceed 30 to 50 available tools. On their internal MCP evaluations, switching to on-demand tool loading (so the model only sees the handful of tools it needs) lifted Claude Opus 4 from 49% to 74% accuracy, and Opus 4.5 from 79.5% to 88.1%.

That is the same model, with the same tools available. The only change is how many definitions it has to read at once.

It pays less attention to what matters

Chroma's context rot study tested 18 current models, including Claude, GPT and Gemini, and every one got less reliable as its input grew, even on simple retrieval tasks. In one test the models answered questions from a focused prompt of around 300 tokens and from a full prompt of around 113,000 tokens with the same answer inside. Every model family scored significantly higher on the focused version.

They also found that adding text that was close to the topic but did not answer the question pulled performance down further. A list of fifty tool descriptions, most of them irrelevant to the job in front of the model, is exactly that kind of noise.

It has more room to make things up

Put those together and you get the failures everyone who uses agents has seen: calling a tool that is close to right but not quite, passing a parameter that does not exist, or confidently reporting a result that never came back. Not all of that is the tool list's fault, but a model with a clean, focused context leaves itself much less room to go wrong.

Why a CLI does not have this problem

Nothing loads until it runs. A coding agent already has a terminal. A command-line tool adds nothing to the session until the agent calls it. When it needs to know how a command works, it runs --help on that one command and reads a few hundred tokens, not a schema for every command the tool has.

The agent already knows the shape. Models have seen an enormous amount of shell usage. Flags, pipes, exit codes and --help are familiar territory, not a new schema to learn mid-conversation.

Output gets filtered before the model sees it. A CLI's output can go through jq, grep or head first, so only the answer reaches the model. Anthropic made the same point about code execution with MCP: one workflow dropped from about 150,000 tokens to about 2,000 by keeping tool definitions and intermediate data out of the model's context. A CLI gets that for free.

It is faster and cheaper. Fewer tokens processed on every turn means quicker responses and a smaller bill. Anthropic notes that loading every definition up front "slows down agents and increases costs". Scalekit ran 75 head-to-head runs on GitHub tasks: answering "what language is this repo?" took 1,365 tokens with the gh CLI and 44,026 with GitHub's official MCP server. The CLI runs completed every time; the MCP runs succeeded 72% of the time.

It is easy to debug. A CLI is one binary. There is no server to run, no transport to debug, no session to keep alive. When something breaks, I run the same command in my own terminal and see exactly what the agent saw. And the same tool that lets an agent append to a Notion page lets me do it from a script, which means it gets used, which means it gets fixed.

Where MCP still makes sense

To be fair to MCP, it is the better choice in some places. If many people need to sign in to a hosted tool with their own accounts, MCP's per-user OAuth is a real advantage. If the client has no terminal, such as a desktop chat app, a CLI is no use at all. And the protocol is catching up: on-demand tool loading closes a lot of the gap. Scalekit, who ran that benchmark, still use MCP for exactly those multi-user reasons.

For my own work, which is one person and a coding agent in a terminal, the CLI wins on every count that matters.

What makes a CLI usable by an agent

The notion-cli and inggest-cli repositories are the public ones. Xero and Outlook follow when I have cleaned them up. They all follow four conventions, because an agent cannot ask a terminal a clarifying question.

A JSON envelope on every command. Every command can return the same shape: ok, data, error. An agent parses that once and never has to scrape text. Humans get a readable table by default; --json flips the envelope on.

Exit codes that mean something. Zero for success. Distinct non-zero codes for auth failure, validation error, not found, and rate limit. An agent can branch on the code without reading the message, which is the difference between "retry with backoff" and "stop and ask".

OAuth with PKCE, tokens in the keychain. Login opens a browser once. Tokens live in the operating system keychain. No secret is ever written to a file that an agent might read, log or commit.

Composite commands for the repeated jobs. The things an agent does over and over (find a page by title and append to it, replay a failed run with the same payload) are single commands. Making an agent chain five calls to do one job is where things go wrong.

Sources

If you want to use them

Install instructions and the full command list are on the open source page. Issues and pull requests are welcome. If you are building something similar and want to compare notes, get in touch.

Newsletter

Getthenextonebyemail

One email when a new article or case study goes up. No drip sequence.

Next step

Tellmewhatyourbusinessrunsontoday

A 30 minute call. You describe the spreadsheets, the apps and the paperwork; I tell you what I would build and roughly what it would cost.