Why Your AI Agent Wastes Most of Its Context Window on Tools
You connect your agent to 50 MCP tools. It can query databases, call APIs, read files, send emails, browse the web. On paper, it has everything it needs. In practice, half your production incidents trace back to tool use—wrong parameters, blown context budgets, cascading retry loops that cost ten times what you expected.
Here's the part most tutorials skip: every tool definition you load is a token tax paid upfront, before the agent processes a single user message. With 50+ tools connected, definitions alone can consume 70,000–130,000 tokens per request. That's not a corner case—it's the default state of any agent connected to multiple MCP servers.
The naive approach treats tool use as a solved problem. Add tools, write schemas, watch the agent call them. That works fine at small scale. It falls apart the moment you connect real enterprise tooling: CRM systems with 40 endpoints, internal APIs with ambiguous overlapping functions, MCP servers that each bring a hundred definitions. At that point, you're not building an agentic system—you're building a very expensive context pollution machine.
This post is about the three compounding bottlenecks that break production tool use, and the architectural patterns that actually address them.
Bottleneck 1: Context Window Pollution
Tool definitions are prose. JSON schemas with descriptions, parameter explanations, usage notes. They read like documentation because they are documentation—the model needs to understand each tool to use it correctly.
The problem is that this documentation consumes context before any work happens. A minimal tool definition might be 200 tokens. A well-documented tool with parameter descriptions and nested schemas might be 800. Multiply by 50 tools and you've spent 10,000–40,000 tokens before the conversation starts. Multiply by 100 tools and you're looking at context that's completely full before the user's first message.
The practical consequence isn't just cost—it's quality. Models lose reasoning coherence as context fills. Conversation history gets evicted to make room for definitions. The agent can no longer see what happened three turns ago because tool schemas took that space. Performance degrades in a way that's genuinely difficult to debug because the degradation is gradual, not sudden.
The fix: lazy tool loading. Don't load all tool definitions upfront. Load only the tools the agent is likely to need for this specific task, then discover additional tools on-demand as needed. The implementation pattern: mark tools as deferred and provide a small "tool search" capability that the model can invoke to retrieve full definitions for tools it identifies as relevant.
The numbers here are significant. Reducing from 50 tool definitions to 3–5 per request can drop per-request token consumption by 85% and increase the usable context window by 50%. More importantly, because deferred tools don't appear in the initial prompt, they don't interfere with prompt caching—you keep cache hits on your system prompt even as tool availability expands.
The catch is that lazy loading places high demands on tool naming and description quality. When the model searches for tools, it's doing semantic matching against tool names and summaries. query_db and fetch_records look like synonyms. search_customer_orders_by_date_status_and_amount is self-documenting. Your tool registry quality directly determines discovery accuracy.
Bottleneck 2: Inference Overhead from Sequential Calls
The standard agentic loop is: reason, call a tool, receive result, reason again, call the next tool. For a workflow that needs 20 tool calls, that's 20 inference passes. At $0.01 per 1,000 input tokens and a 4,000-token context, you're spending $0.80 per workflow—before counting the intermediate results accumulating in context.
The deeper problem is what those intermediate results do to context. A budget compliance check that reads 2,000 expense line items doesn't need to return all 2,000 items to the model's reasoning context. It needs to return: "47 violations found, $12,400 in flagged expenses, 3 require immediate escalation." The model doesn't benefit from seeing every line item—it benefits from the synthesized result.
Two patterns address this.
The first is parallel tool calling: issue multiple independent tool calls simultaneously rather than sequentially. Fan-out, then fan-in. When your agent needs to check account status, verify inventory, and look up pricing before responding, there's no reason to do these serially. Dispatch all three in parallel, aggregate the results, proceed with a single reasoning step. This doesn't reduce the total number of inference passes, but it dramatically cuts wall-clock latency and prevents intermediate results from accumulating unnecessarily in context.
The aggregation rules matter here. Parallel calls that return partial, conflicting, or incomplete results need explicit merge logic. Without it, you get "loudest output wins" behavior—the most verbose tool result dominates the model's reasoning even if it's less relevant. Define what a successful merge looks like before you need to debug a failed one.
The second pattern is code-orchestrated execution. Instead of calling tools sequentially through the agentic loop, the model writes a short code block that orchestrates multiple tool calls, processes the results programmatically, and returns only the synthesized output. The model doesn't see the intermediate results—only the final answer.
For the budget compliance example: instead of 20 inference passes with 50KB of expense data in context, you get one code block, one execution, and a 1KB summary. Measured against real workflows, this pattern can cut token consumption by 35–40% on complex multi-step tasks and improve accuracy on benchmarks that require aggregating information from many sources.
The tradeoff: the model needs to be capable enough to write correct orchestration code, and you need a safe execution sandbox. This isn't appropriate for simple single-tool calls or situations where the model genuinely needs to reason over intermediate results. It excels at: aggregating large datasets, workflows with 3+ dependent calls, any time you'd otherwise be filling context with raw API responses.
Bottleneck 3: Parameter Ambiguity
JSON schemas validate structure. They cannot express intent.
A schema says date is a string. It doesn't say whether that string should be 2025-01-15, January 15, 2025, 15/01/2025, or 1705276800 (Unix timestamp). A schema says filter is an optional object. It doesn't say that you should always include it when querying large datasets to avoid timeouts. A schema says currency has a valid enum of ["USD", "EUR", "GBP"]. It doesn't say that cross-border transactions require explicit currency specification even when defaulting to USD.
This is the silent failure mode in production tool use. The call is structurally valid. It passes schema validation. The API returns an error, or worse, returns unexpected results that the model treats as correct.
The standard prescription—"write better descriptions"—is right but incomplete. Descriptions explain what a parameter does. Examples show how it should be used in context.
Concrete examples dramatically outperform descriptions alone. The pattern: for each tool with non-obvious parameters, include 3–5 usage examples showing minimal valid calls, partial specifications with specific optional parameters, and full specifications for complex cases. Use realistic data—actual city names, plausible prices, real-looking IDs. The model generalizes from examples in ways it doesn't from abstract documentation.
Measured improvement: in tasks requiring complex parameter handling, adding concrete examples moves accuracy from the 70% range into the 85–90% range. That's a 15–20 point improvement from a documentation change that takes an hour to write.
The effort is front-loaded. Write the examples once, include them in your tool registry, and every call benefits. The alternative—debugging parameter errors in production—is both more expensive and less systematic.
Designing Tool Interfaces for Production
Beyond the three bottlenecks, a set of interface design principles separate tools that work reliably from tools that create ambiguity:
Return minimal, synthesized outputs. Most tools return more than the model needs. A search tool returning 10 full documents when the model needs 1–2 relevant excerpts is filling context with noise. Include a reason_code or confidence field when relevant. Often a well-structured minimal response eliminates a follow-up call entirely.
Require explicit reasoning before calls. Prompting the model to state a one-line reason before each tool call and a brief observation after each result improves traceability and reduces reasoning loops. It forces the model to articulate why it's calling a tool, which catches cases where it's reaching for a tool out of habit rather than necessity.
Build rejection gates. Every tool call should pass through validation before execution. Reject malformed calls early with an explicit error message, not a silent failure. The model can recover from a clear error; it cannot recover from an API call that succeeded but did nothing.
Treat prompt injection as the SQL injection of tool use. If your tools accept natural language parameters that get executed downstream, you have an injection attack surface. Implement denylist sanitization, validate parameters against expected patterns before execution, and treat unexpected input structures as potential attacks rather than edge cases.
Parallel Tool Calling in Practice
Parallel tool use changes the architecture in ways that go beyond just "call multiple tools at once."
The planning model and executing model can be different sizes. A large model is good at determining what to do in parallel—decomposing a task into independent subtasks, identifying which operations can run concurrently without conflicting state. A smaller model can handle the actual execution of each targeted call. Planner + executor splits let you use compute efficiently: expensive inference where strategic reasoning matters, cheaper inference for routine execution.
Per-branch budgets prevent runaway costs. In a parallel workflow, each branch can independently accumulate context and make additional calls. Without explicit budgets—maximum tokens, maximum calls, maximum latency—one expensive branch can blow your entire session budget while the others complete trivially. Set hard limits on each parallel branch and enforce them.
Evidence grounding prevents the aggregation problem. When results from parallel branches get merged, require that each contributing result include a provenance marker: which tool, which call, which parameters. This makes post-hoc debugging tractable and prevents merged summaries from losing the source they came from.
Where This Is Heading
The speculative execution approach—pre-firing predicted tool calls based on historical patterns before the model explicitly requests them—has demonstrated 48% task completion time reduction in research settings. The idea is similar to CPU branch prediction: you pay for wrong predictions but win big on correct ones. It's not widely deployed in production yet, but the pattern will matter as workflows standardize.
The MCP ecosystem maturing as a standard (now supported across the major providers) means tool definitions will increasingly be reusable across agents, organizations, and workflows. That shifts tool design from a local engineering concern to something closer to API design—interfaces that others depend on, with versioning, migration paths, and stability guarantees.
The deeper shift is that tool use quality is becoming the primary differentiator between agents that work and agents that look like they should work. Model capability differences are narrowing. Context window limits are expanding. What remains is the unglamorous work: tool definition quality, lazy loading architecture, example coverage, validation gates. That's where production reliability is actually built.
The 50-tool agent connected to everything is not the mature version of agent design. It's the draft. The mature version loads 5 tools per task, generates synthesized outputs, and fails loudly enough that you can fix it.
- https://arxiv.org/html/2603.18897v1
- https://martinfowler.com/articles/function-call-LLM.html
- https://sparkco.ai/blog/advanced-tool-calling-in-llm-agents-a-deep-dive
- https://www.stackai.com/insights/ai-agent-architecture-patterns-sequential-parallel-and-hierarchical-workflows
- https://cookbook.openai.com/examples/agents_sdk/parallel_agents
- https://www.promptingguide.ai/agents/function-calling
- https://datasciencedojo.com/blog/agentic-llm-in-2025/
- https://thenewstack.io/5-key-trends-shaping-agentic-development-in-2026/
- https://link.springer.com/article/10.1007/s41019-025-00296-9
- https://research.ibm.com/publications/evaluating-llm-based-agents-foundations-best-practices-and-open-challenges
