Skip to content

Progressive discovery

The usual way to put a command-line tool behind MCP is to turn every command into a tool. It is direct and it is what the first generation of Cobra bridges did. It also scales badly in the one dimension that matters to a model: a client fetches the whole catalogue, schemas included, and carries it in the context of every conversation. A tool with eighty commands ships eighty schemas before the user has typed a word, and most of them are never used.

This module's default is to publish three tools instead, whatever the size of the catalogue: search_tools, get_tool_details and call_tool. The model searches (or browses an empty query), inspects the one operation it needs, and calls it. A schema enters the conversation when it is about to be used, and only that schema. The catalogue can be as large as the tool, and the context cost stays flat.

Why it is an application pattern, not a protocol feature

Nothing in MCP knows about this. To a client, call_tool is an ordinary tool that happens to take a name and an arguments object; discovery is a convention the server and the model agree on through the tool descriptions. That is why compact mode works with every client that speaks MCP, and also why it carries a trade.

The trade: approval

A client that asks before running a destructive tool asks about the tool it can see. In compact mode that is call_tool, so its annotations have to be conservative (destructive, open-world), and every operation behind it inherits that prompt. The per-operation hints an application declares still exist and reach the model through get_tool_details, and reach a host through the registry, but they do not reach the client's own approval UI.

Direct mode gives that UI back. Each operation is its own native tool with its own annotations, at the cost of the catalogue being pushed up front. It is an explicit choice at server construction (WithMode(Direct)), never inferred from the client, and the same registry and policy serve both. Choosing a mode is the practical guide.

What discovery is not

Search is not a gate. A known operation may be invoked without a prior search, and inspecting an operation grants no permission to run it. Discovery, inspection and execution each consult the host's policy; execution consults it again with the validated arguments even when inspection just succeeded. A denied name and an unknown name produce the same answer, so the catalogue cannot be probed. Registry membership is not authorisation.

Search is bounded: five summaries by default, twenty at most, a 256-byte query, a 16 KiB page, and cursors that are encrypted, scoped to the caller and expire after ten minutes. These are starting policies from spec 0001 (OQ6), tuned against a synthetic thousand-operation catalogue rather than a real workload, and the reference pages state the exact numbers.