Which tools the model sees
Docs/Extend/Which tools the model sees

Which tools the model sees

Edit on GitHub
docs-site/extend/tool-offer.md

The model is told every tool in its visible set in each prompt: the tools that exist, narrowed by the scope and by what policy would not deny. Every description costs tokens on every pass, so an extension can narrow what this session's model is told, and choose how the rest is offered.

Hide and show

await ctx.tools.hide(["mcp.github.*"]);   // hide from this session
await ctx.tools.show(["mcp.github.*"]);   // lift it again

Rust: tools_hide(names) and tools_show(names) on the host handle.

  • An extension lifts only its own hides. It cannot show a tool the visible set excludes: a role never widens what a step is granted.
  • The offer changes at turn boundaries only, never in the middle of a pass, so the cached part of the prompt changes at most once per turn.

Choose how tools are offered

By default every visible tool is declared in the prompt, as it always was. A selector chooses which are declared and which are only searchable:

[tools]
selector = "lazy"
toolSelector: {
  name: "lazy",
  select(visible, host) {
    const declared = visible.filter((t) => t.name.startsWith("builtin.")).map((t) => t.name);
    const searchable = visible.filter((t) => !declared.includes(t.name)).map((t) => t.name);
    return { declared, searchable };
  },
},

The selector returns two lists, both subsets of the visible set. Anything else it names is dropped. It runs once per turn, so it costs one round trip per turn.

Search for the rest

When some tools are searchable, the model finds them with the core tool tools.search. The search answers the tools that match within its own visible set. A call to a searchable tool must follow a search that found it, in the same turn.

The core tools ui.show and ui.hide are searchable as well, so their schema is not in every prompt. What the agent places stays in its history, and costs tokens on later turns (The agent's route).

An MCP server can be made searchable from its own table, so a large server does not fill every prompt:

[mcp_servers.github]
command = "github-mcp-server"
args = ["stdio"]
deferred = true

See MCP servers.

Cost

None by default. A selector costs one round trip per turn. Deferred and hidden tools shrink every prompt, which is the point.

Config keys

  • [tools] selector names the selector. A name nothing registered fails at start.
  • [mcp_servers.<name>] deferred makes that server's tools searchable.

Both are in Config keys.