How AI Agents Keep 400 Tools From Eating the Context Window
Agent tool counts are ballooning as MCP servers expose hundreds of domain-specific functions. Without on-demand loading, context windows fill with tool definitions instead of conversation, driving up latency and cost while shrinking the effective working memory available for actual problem-solving.
When an AI coding agent connects to multiple MCP servers, the tool list can easily hit 400 entries. Sending every tool's full JSON Schema with every API call burns 64,000 tokens before a single user message arrives—half a 128k context window gone. Tool search solves this by keeping only a name list in the system prompt and loading a tool's schema only when the model requests it.
The mechanism splits tools into two tiers. Core tools like readFile, edit, and shell ship with every request because nearly every task needs them. Everything else—web search, GitHub operations, hundreds of exchange-trading functions—sits in a deferred catalog. The model sees the names, calls a built-in toolSearch function with keywords or an exact select: match, and the client injects the full schema into the next round's tools array.
Claude Code, Codex, and x-code-cli all implement this pattern with minor differences in matching algorithms and how activated schemas reach the model. The trade-off is one extra API round-trip the first time a deferred tool is used, but activated tools persist for the session. A threshold check prevents the overhead from kicking in when the tool list is small enough to fit comfortably.
Tool search is a client-side strategy, not an MCP protocol feature. The protocol's tools/list still returns everything; the client unilaterally decides what to defer, which means every Agent CLI must build its own implementation.
The semantic quality of tool names is load-bearing. Names like mcp__github__create_issue carry enough meaning for the model to pick the right tool from a flat list; if tools were named tool_001 through tool_400, the whole scheme collapses.
x-code-cli's model-compatibility check is a blunt string match on names like 'haiku' or 'nano', which can't distinguish Claude 3 Haiku from the far more capable Claude 3.5 Haiku. Codex's per-version boolean flag in models.json is the more precise approach.
The stale deferred list in the frozen system prompt creates a subtle state inconsistency—the prompt says a tool isn't loaded when it is—but strong models rarely trip over it because they remember the tool_result from the activation round.
Prefix caching economics shift with tool search: the cache misses only when a new tool is activated, then stabilizes. Without deferral, the cache is stable but the baseline cost is permanently higher.