Burrow used to hand your AI coding agent an MCP server. Today it hands the agent a small command line tool called burrow-agent instead. That is a real reversal, and it deserves a real explanation, because MCP is a good standard and this is not a post about MCP being bad. It is a post about a narrow, specific fit: for an operations control surface with a lot of verbs, a composable command the agent runs on demand fits better than a server whose tool list sits in the agent's context on every turn. Let me walk through what actually happens when you load an MCP server, what it costs, and why the shape of a CLI turns out to suit this job.

What loading an MCP server into a session actually does

MCP, the Model Context Protocol, is Anthropic's open standard for giving an AI model tools it can call. You run a small server, you point the agent at it, and the server advertises a set of tools. Each tool has a name, a description, and a schema that spells out its arguments. When you connect that server to a session, the agent learns those tools by reading their definitions. Claude, for example, receives the tool list and can then call any of them by name with structured arguments.

That is genuinely useful. It is why MCP took off: it is a clean, model-neutral way to say "here are the things you can do," and any agent that speaks the protocol can use any server that speaks it. For a focused server with a handful of tools, it is close to ideal.

The thing to understand is where those tool definitions live. To decide whether to call a tool, and how, the model has to be able to see it. So the tool list becomes part of the material the model reasons over. In the simplest arrangement, every tool's name, description, and argument schema is present in the session, and it is present every turn, whether or not you are about to use any of it. The agent is carrying the menu around even when nobody is ordering.

The context cost, told honestly

Here is where I want to be careful, because the loudest version of this argument is a little overstated and I would rather give you the accurate one.

The loud version is "MCP pollutes my context." You hear it a lot. And there is a real effect underneath it: an operations surface is not a handful of tools. Burrow's operate surface covers deploying, rolling back, scaling, autoscaling, reading logs, querying logs and metrics, checking status and reachability, listing and setting config, managing add-ons and backups, routing and domains, the audit log, and a guarded delete. That is a couple dozen verbs, each with arguments and prose describing when to use it. Turned into always-present tool definitions, that is a standing weight in every session, spent whether the agent operates anything that turn or just answers a question about your code.

The honest correction is that this is not as fixed as the loud version implies. Newer clients can load tool schemas on demand rather than keeping the whole set resident, which trims the footprint a lot. So part of "MCP pollutes my context" is really a perception, shaped by how some clients used to behave, more than a hard and permanent cost.

But notice something about the fix. Schema on demand works by not keeping the tools resident until they are needed. That is worth sitting with, because it is most of the argument for a CLI. If the good outcome is "nothing is loaded until the agent actually reaches for it," then a command the agent runs on demand gets you there by construction. Nothing about burrow-agent is resident in the session at all. There is no tool list to keep or trim, because there is no server advertising one. The agent runs a command when it has something to do, reads the result, and moves on. The context cost is exactly the command it just ran and the output it got back, and nothing else.

The real gap is composition, not just footprint

Context footprint is the argument everyone reaches for first, but it is not the one that actually decided this. The one that did is composition.

An MCP tool call is call and response with a fixed result. The agent calls a tool, and it gets back one blob. It cannot pipe that blob into another command. It cannot slice it with jq, filter it with grep, or page it with head without pulling the whole thing into its own context and doing the work there by hand. Chaining one tool's output into another tool's input means round tripping every intermediate result through the model. The tool call channel simply does not offer composition, because a fixed result is not something you can compose.

Composition is the native idiom of the place a coding agent already lives: a shell. Agents are good at shells. They pipe, they filter, they chain, they read exit codes. That is a capability they already have and use constantly, and an MCP server cannot tap into it. A command line tool can, because it is the shell.

So burrow-agent prints its results as JSON, and the agent composes them the way it composes everything else. Want just the error lines out of a log?

burrow-agent logs web | jq '.lines[] | select(.message | test("error"))'

Want to page a long result, or pull one field, or feed the output of one command into the argument of the next? That is all ordinary shell work now, and the agent does it without asking Burrow for a special tool shaped exactly to that question. A fixed MCP result cannot be sliced after the fact. A JSON stream out of a command can be sliced any way the agent needs, on the spot, with tools it already knows. That is the capability the tool call channel structurally lacks, and it is the reason for the change.

What the CLI looks like in practice

burrow-agent is the agent's control channel to Burrow. It carries the operate verbs and nothing dangerous. The agent runs it directly, the same way it runs any other command in its environment.

Deploy by image reference:

burrow-agent deploy web --image ghcr.io/you/web:2.4.0

Check what is running:

burrow-agent status web

Read recent logs, or search across time if you have the logs add-on:

burrow-agent logs web
burrow-agent logs-query 'error'

Scale, roll back, run a one off task in the app's own environment:

burrow-agent scale web 3
burrow-agent rollback web
burrow-agent run web -- ./migrate up

Every one of these prints indented JSON, so the agent can read it as prose or compose it with jq. Run any command with -h and it describes itself in full, which is how the agent discovers the surface: it reads help, rather than loading a schema list up front.

One binary to install, and no server to run

There is a plainer benefit that matters more than it sounds. An MCP server is a second thing to stand up. You install it, you wire it into the agent's configuration, and you keep it current. It is a process that has to be running for the agent to do anything.

burrow-agent is one binary on the agent's path. You install it, you run one command to wire your agent's permissions, and that is the whole setup. There is no server to keep alive, nothing to reconnect, nothing to configure beyond the credential it uses to reach the control plane. For the person getting started, that is one fewer moving part on day one. For the running system, it is one fewer process that can be down when you need it.

One surface to maintain, not two

There is a quieter cost to running an MCP server that only shows up over time. Burrow has always shipped a human command line tool, burrow, for the person at the terminal. When the agent's surface was a separate MCP server, every new operate verb had to be built twice: once as a CLI command and once as an MCP tool, each documented and tested on its own. Two surfaces that are supposed to do the same things will drift. One gets a flag the other missed. A description goes stale on one side. The behavior diverges in some corner, and now the agent and the human are operating the same system through two subtly different windows.

Collapsing the agent's surface into a command tool removes that tax. There is one place the operate verbs live, so the agent and the human are looking at the same behavior, and there is nothing to keep in sync because there is nothing running in parallel. Everything the agent does through burrow-agent has a plain human equivalent in burrow (burrow app deploy, burrow app status, burrow app rollback, and so on). The agent's tool is the same operations, scoped down and JSON first so an agent can compose the result. That is a maintenance win, but it is also an honesty win: what the agent can do and what you can do are the same list, not two lists that happen to mostly agree.

A stronger safety boundary, by construction

Pointing an agent at a live production system is a real thing to be nervous about, and the shape of the tool matters for safety too.

burrow-agent is capability reduced on purpose. The dangerous admin verbs are not in it. There is no install, no cluster setup, no command that writes a credential, and, deliberately, no command that sets a secret value or reads one back. Those verbs are not disabled at runtime, they are simply not compiled into the binary. The agent cannot express an operation the binary does not contain.

That is a stronger boundary than the usual "deny that command in the agent's settings." A deny rule is a convention some runtime has to honor at call time, and conventions can be misconfigured or bypassed. A binary that structurally lacks the verb cannot perform it no matter what the runtime does. The safety moves from a rule you hope is enforced into the shape of the artifact itself. Behind that, the control plane still holds every cluster credential and still enforces the guardrails server side, so a risky operation like a prod deploy or a delete is held for your confirmation regardless of which tool asked. The CLI is a thin, credential free client. It holds none of the keys.

The honest, narrow claim

I want to end where I started, because it would be easy to read this as "MCP bad, CLI good," and that is not the claim.

MCP is Anthropic's open standard and it is the right tool for a lot of jobs. If you are exposing a small, focused set of tools, or you want the model neutral tool discovery that MCP gives you out of the box, or your surface is a few verbs rather than a few dozen, an MCP server is a fine and often better choice. Plenty of what Burrow's own agent does elsewhere is a good fit for a tool call. None of this is a knock on the protocol.

The claim is narrow and specific. For an operations control surface, one with many verbs, where the agent's real advantage is that it can pipe and filter and chain results in a shell it already knows, a composable command the agent runs on demand fits better than an always present server whose tool schemas sit in context every turn. You get composition, which the tool call channel cannot offer. You get nothing resident until the agent acts, which is the same outcome schema on demand chases, reached by construction. You get one binary instead of a server to run. And you get a capability reduced surface that is safer by its shape, not by a rule you hope holds.

Those are the reasons Burrow made the switch. Not because MCP is wrong, but because the job is operating real applications through an agent, and for that job the composable command is the better fit. The agent already lives in a shell. Meeting it there, with a tool it can compose, turned out to be the right call.