Skip to main content

Your Agent Is Drowning in Tool Definitions (Code Execution Throws It a Rope)

· 6 min read
TheMCPGuy
MCP Developer & Educator

An overflowing context window stuffed with tool-definition JSON on the left, a slim code file on the right, tokens dropping from 150,000 to 2,000

Here is a cost nobody warns you about when you wire up your fifth MCP server: your agent gets dumber and more expensive at the same time, and it happens before the user has typed a single word.

The reason is boring and brutal. Every tool your servers expose ships a definition: a name, a description, a JSON schema for its inputs, often examples. All of it gets serialized into the model's context window on every single turn, just so the model might pick the right tool. Connect a few busy servers and you are spending six figures of tokens describing tools the model will never call for this particular request.

Version disclosure (as of June 2026)

The pattern in this post is described in Anthropic's engineering write-up "Code execution with MCP" (November 2025) and targets the MCP spec 2025-11-25. Token figures below are illustrative numbers from that article, not a benchmark you should quote as gospel, so measure your own. As the spec and SDKs evolve, the shape of this technique should hold, but verify the mechanics against the current docs.

The tax you didn't know you were paying

There are actually two separate bloat problems, and conflating them is why people "optimize" the wrong one.

1. Definition bloat (up front). Before any work happens, the client loads every tool definition from every connected server. This is fixed per turn and scales with how many tools you have connected, not with what you are doing. Three hundred tools at ~500 tokens each is ~150,000 tokens of overhead on turn one.

2. Result bloat (at runtime). A tool returns 4,000 rows of JSON, the model needs three of them, and the other 3,997 sit in the transcript forever, getting re-sent on every subsequent turn.

Definition bloat makes your agent expensive and slow and dumber, because a context window crammed with tool schemas has less room for the actual problem, and models genuinely degrade as the relevant signal gets buried. Result bloat compounds it turn over turn.

The fix: stop describing tools, start importing them

The technique Anthropic documented flips the model's relationship to your tools. Instead of presenting every tool as a definition the model reads and then calls via JSON, you present your MCP servers as a filesystem of code, a directory of typed functions the model can import and call from inside a sandboxed code-execution environment.

// The model doesn't see 300 tool schemas.
// It sees a filesystem and writes code against it:
import { getInvoices } from "./servers/billing";
import { getCustomer } from "./servers/crm";

const overdue = (await getInvoices({ status: "overdue" }))
.filter(i => i.daysLate > 30);

// Only the 3 rows it needs ever re-enter the context, not 4,000.
console.log(overdue.map(i => ({ id: i.id, customer: i.customerName })));

Two things just happened:

  • The model only loads the definitions it actually imports, also known as progressive disclosure. The other 295 tools cost nothing this turn.
  • The model processes results in code and returns only the slice it cares about, so result bloat collapses too.

Anthropic's worked example moved an agent from roughly 150,000 tokens to roughly 2,000 for the same task, about a 98.7% reduction. Treat that as "an order of magnitude or two, in a favorable case," not a number to put on a slide.

Progressive disclosure is the real idea

"Code execution" is the mechanism; progressive disclosure is the principle, and it long predates MCP. Don't put everything in front of the model at once. Let it discover the tool surface lazily: list what's available cheaply, load the full signature of a tool only when it intends to use it, fetch only the fields a step needs.

You can apply the principle even without a full code sandbox:

  • Group tools and load definitions per-group on demand instead of all at once.
  • Return compact, paginated, or summarized results by default and offer a "drill in" tool for detail.
  • Keep large payloads as resources the model references by handle, not as inline tool output it has to carry forever.

So who is supposed to fix this, you or the client?

This is the honest nuance the headline glosses over: a lot of definition bloat is the client's problem, not your server's. How tool definitions are packed into context, whether the host supports a code-execution surface, whether results can be offloaded to resources, much of that lives in the MCP host, not your server.

What you control as a server author:

  • Right-size your results. Default to lean; make verbosity opt-in.
  • Lean on resources for big data instead of stuffing it through tool outputs.
  • Write tight definitions (see Your Tool Description Is a Prompt; every wasted word is a wasted token, on every turn).

What you control as a host/client author:

  • Whether you expose tools as schemas-in-context or as an importable code API.
  • Whether you implement progressive disclosure of definitions at all.

What to do Monday

  1. Measure first. Log the token count of your tool definitions on a cold turn. People are routinely shocked.
  2. Cut definition bloat before you touch anything clever: fewer, sharper tools; tighter descriptions.
  3. Move big results to resources so they stop riding along every turn.
  4. If your host supports it, try the code-execution surface on your most tool-heavy agent and measure the delta on a real task.

The agents that win in 2026 aren't the ones connected to the most MCP servers. They're the ones that can ignore the most servers, cheaply, until the moment a tool is actually needed.

Want the full treatment? This is the heart of our upcoming Context Engineering for MCP course, covering token accounting, code execution, progressive disclosure, and how to measure the savings instead of trusting a blog post's numbers (including this one).