Overview
June 9, 2026

The answer is almost always a CLI

I have some standing to write this one. Anthropic announced the Model Context Protocol in late November 2024; by early December I had shipped MCP Manager, one of the first tools for wiring MCP servers into Claude Desktop, back when configuration meant hand-editing a JSON file and one missing comma silently broke everything. I was early because the promise was real: for the first time, an agent could reach out of the chat window and touch your actual data, with every API wrappable into tools a model could call. For a while it was the most exciting surface in the ecosystem.

Then everybody and their mother wrote an MCP server, and the costs showed up. Today, nearly every tool I build for my agents is a CLI instead. But this isn’t the polarized take you’ve already read from both directions. MCP kept a property that nothing else has, and most of the CLI-versus-MCP discourse misses it entirely.

The protocol ate the context window

MCP’s original sin is that every connected server front-loads its full tool schemas into the context window, whether or not the conversation will ever touch them. Schemas are verbose by design, so the tax compounds fast: a representative measurement found seven connected servers consuming 67,300 tokens, a third of a 200k context window, before the user typed a word.

The clearest evidence of how bad this got is who had to fix it. Anthropic shipped a Tool Search Tool: tools load deferred, and Claude runs a search to discover what it has before it can call anything. Cloudflare shipped Code Mode: convert the MCP tools into a typed API and have the model write code against it, an entire API surface in about a thousand tokens. Both are clever. Both are also the protocol’s designers teaching the model not to load the protocol. Claude Code today genuinely does not know what tools it has until it goes looking. That’s the accommodation we made rather than admit the schemas never belonged in context in the first place.

Agents already know how to use a computer

Meanwhile, the alternative was sitting in the training data all along. My core belief about agents, the one gooselake is built on, is that agents doing real work need a computer, and the value of a computer is that general capability compounds: run commands, write files, write code to solve the problem in front of you.

CLIs inherit that generality, and they come with something MCP can never have: priors. A model has read every man page and help menu in its training data. Hand it a CLI it has never seen and it doesn’t need teaching. It runs --help, reads the menu, recurses into subcommands until it finds the verb it needs. I described this in the Go post as the documentation problem disappearing: cf-cli grows new subcommands and no instructions anywhere need updating, because the interface is the documentation and it can’t drift.

Now run the comparison. An MCP schema change means rewriting the instructions and skills that reference it; the knowledge about the tool lives outside the tool. A CLI change updates its own help output; the knowledge ships with the binary, the way it has for humans for fifty years. One of these is self-documenting infrastructure; the other is a contract you have to keep re-teaching.

I didn’t reason my way here abstractly; I migrated. My early agent helpers were all MCP servers, and webctx spent the first six months of its life as one, bloating every session that connected it. It became a TypeScript CLI when I understood the context cost, then a Go CLI when I understood the distribution cost. Each step made it cheaper for the agent, easier to install, and better documented, without a line of instruction anywhere.

What MCP still owns

Two things, and they’re real. The first is portability: an MCP server deploys anywhere and any client can connect, which is how remote agents that will never have a shell, such as ChatGPT and claude.ai, plug into agentbox over the same protocol from anywhere. If your consumer doesn’t have a computer, the CLI argument evaporates by definition.

The second is the one the discourse misses: MCP is stateful, and statefulness is a feature you can’t fake with a stateless binary. It’s in the protocol’s bones: a session begins at initialization and persists across every subsequent call; the Streamable HTTP transport literally issues an Mcp-Session-Id that clients must present on every request. An MCP connection knows who you are for its whole lifetime. That gives you authentication semantics, caller identity, and an answer to “who called what, when” as protocol-level properties rather than things you bolt on. A CLI invocation is an anonymous process with arguments; if you want it to carry identity, you’re building an auth workaround.

Why goldengoose’s own tools are MCP

Which brings me to the choice that looks like it contradicts this whole post: every internal tool in goldengoose, including team management, agent messaging, and the process manager, is MCP. Deliberately. Two reasons, and both are the exceptions proving the rule.

First, I wanted the opposite of tool search. I hated deferred discovery from the moment I saw it: when I tell my lead to add an agent, I want zero lookup latency between intent and action, with the schema already in context and the call immediate. That’s affordable precisely because I keep the discipline that makes it affordable: six tools, three for teams and three for processes, schemas small enough that always-in-context costs almost nothing. The bloat problem was never MCP connections; it was undisciplined surfaces. Keep the surface tiny and the protocol’s always-loaded property flips from tax to feature.

Second: state, exactly as advertised. The gg-mcp-server runs as a sidecar within the app, in-process with the Rust runtime, which means every tool call arrives through a session the runtime owns. When one agent messages another or adds a teammate, the runtime attaches who did it, from which session, into delivery tracking and the audit trail, for free. All the delivery semantics I care about, including receipts, attribution, and “who added whom,” fall out of the connection being stateful and authenticated. A CLI could not give me that without reinventing sessions on the side; the same requirement in gooselake became an MCP gateway that requires an active caller session for every invocation, so no tool call is ever anonymous.

So the rule I actually follow, stripped of tribal loyalty: if the agent has a computer and the job is automation, such as DNS edits, search, or moving files between agents, build a small CLI, almost every time. If the consumer has no shell, or the connection itself needs identity, sessions, and an audit trail, that’s what MCP was built for, and it’s excellent at it. Neither camp is right. The answer is almost always a CLI, and knowing precisely when it isn’t is the actual skill.