llmops

Lazy by design: what MCP can learn from -h

Jul 23, 2026 · 5 min read

Every LLM application runs on the same budget: a context window. Everything you put in it costs money, costs latency, and costs attention. A model that sees forty tool schemas picks between them measurably worse than a model that sees five. Token thrift is architecture, not an optimization you bolt on later.

There are two common ways to hand an agent capabilities: give it a shell full of CLIs, or plug it into an MCP server. I wrote earlier about what MCP looks like on the wire. This essay is about what it costs to keep in your head.

The CLI is lazy by design

A command-line tool costs zero tokens until you ask it something. The agent runs myapp -h, gets a short index of subcommands, and only runs myapp export -h once export becomes relevant. That is progressive disclosure in its purest form: a hierarchy of documentation you descend at the moment of need. You pay per question, never per session.

Three other things come with the deal:

  • The hierarchy is self-describing. -h works at every level. The agent doesn't need to know a protocol, just a habit Unix has been reinforcing for forty years. That also means the habit sits deep in every model's training data.
  • Composition is free. myapp export --json | jq '.items[] | .id' does in one pipe what tool calls need three round trips for. Every pipe is a tool call you didn't make, and an intermediate result that never entered the context window.
  • The documentation is human-hardened. The help text of a mature CLI has spent decades being tested against one question: what do I type here? An agent has the same question.

The price list is real, though. There are no typed schemas, so the agent parses free text and sometimes chokes on it. There is no built-in auth story. And you have to give the agent a shell, which is a large attack surface and demands serious sandboxing.

MCP is eager by default

MCP starts from the opposite posture. When a session opens, the client calls tools/list and receives every tool with its complete JSON Schema, and mainstream clients put all of it in the context window. A server with thirty tools easily runs to tens of thousands of tokens of standing cost, paid before a single question is asked and present on every request after that. Prompt caching softens the bill but not the attention problem: the model still sees those thirty schemas every time it decides anything.

two disclosure models: who pays, and when tokens in context before the agent gets to its first answer CLI — lazy by design standing cost: 0 tokens myapp -h + ~150 tok myapp export -h + ~200 tok myapp export --json + result answer ~350 tokens total every one of them asked for MCP — eager by default standing cost: the whole catalog tools/list get_weather {…schema…} search_docs {…schema…} create_issue {…schema…} … 27 more tools ~21,000 tokens paid before the first question is asked
The CLI bills per question, at the moment of use. MCP bills the whole catalog at session start.

So can MCP reveal its specification the way -h does, gradually and on demand? Partly, and only with discipline. There are five mechanisms, and each one gives something up.

1. Pagination. tools/list supports cursor-based pagination at the protocol level. But it was designed for large lists, not relevant ones, and in practice clients walk every cursor to the end and dump the union into context anyway. The mechanism exists; the laziness doesn't.

2. Dynamic registration via listChanged. A server may change its toolset mid-session and notify the client. So you can build a server that starts with three tools and switches on the rest only when session state warrants it, after login, after a project is selected. This is the most protocol-native form of gradualism. Almost nobody uses it that way, and it makes the server responsible for tracking state.

3. The meta-tool pattern. Expose exactly two tools: search_tools(query) and invoke_tool(name, args). The real catalog stays server-side and the agent queries it on demand. Functionally this is -h. But you have effectively set the protocol aside and built your own discovery layer on top of it, and you lose typed-schema validation on the real tools, because the client never learns their shapes.

4. Client-side deferred loading. Anthropic's Tool Search Tool (and the equivalent inside Claude Code) keeps only tool names in context and fetches the full schema when the model searches for it. This is -h for MCP, but it lives in the client, not in the protocol. A server only benefits if the client happens to play along.

5. Code execution over MCP. The approach from Anthropic's engineering blog in late 2025: present each MCP server as a code API on a filesystem, one file per tool, and let the agent read only the files it needs, filtering results in code before they ever reach context. This fixes the schema bloat and the intermediate-result bloat at the same time. It also turns MCP into something that looks a lot like a shell full of CLIs.

The pattern across all five: the CLI is lazy by design, MCP is lazy by discipline. Nothing in the protocol forbids gradual disclosure, but the defaults, the SDKs and the client implementations all push toward eager loading. Every workaround sacrifices something: typed schemas, protocol conformance, or portability across clients.

What MCP actually buys

MCP is a trade, not a mistake. The things a shell doesn't give you:

  • Typed contracts. JSON Schema validation catches malformed arguments before execution. Parsing CLI output stays guesswork.
  • No shell required. Web clients, mobile apps, any environment where handing out bash is not an option.
  • A narrower attack surface. An MCP server exposes exactly N operations. A shell exposes everything the OS allows. For plenty of deployments that settles the question by itself.
  • Auth, streaming, resources, prompts. OAuth flows, long-running operations, subscriptions. Every CLI reinvents these on its own, one tool at a time, usually badly.

The convergence

The comparison is not "CLI good, MCP bad". It is an asymmetry in defaults. The CLI's forty-year-old convention of hierarchical, on-demand help happens to be exactly the interaction model a token-conscious agent needs. MCP has the better type system and the better security story, but its discovery model was built for consumers with infinite memory, and an LLM is not one of those.

The two are already converging: tool search, code execution over MCP, skills that keep only metadata resident in context. All of them are attempts to teach MCP the -h reflex. Until that lands in the protocol's defaults instead of its escape hatches, the working rule stays simple: few, powerful, composable tools, with documentation that is paid for at the moment of use. Whether the payment travels over a pipe or over JSON-RPC is an implementation detail.


Thoughts? Find me on LinkedIn.