Your Agent's Tool Surface Is a Dependency Tree. Audit It Like One.

Most teams haven't caught on yet, but AI agents are running into the same problems with dependency management, and it's surfacing in a new, very troublesome location.
Your Agent's Tool Surface Is a Dependency Tree. Audit It Like One.

When talking with engineers about dependencies, discussions quickly turn to builds and deployments. Each new dependency means more code that has to be shipped. Longer build times and a larger attack surface are just a few consequences of added dependencies. Ultimately, dependence on a dependency becomes a liability, and therefore, it is important to account for those dependencies through the use of lockfiles, audits and SBOMs.

Most teams haven't caught on yet, but AI agents are running into the same problems with dependency management, and it's surfacing in a new, very troublesome location. With each dependency added to an agent, the agent’s context window increases to include the name, description, and input schema for that dependency. In the most common configurations, that's shipped with the agent for every single request, regardless if the tool was even used. Connect a few MCP servers and you're shipping a book of API docs with every single turn in every single conversation.

The data is clear. GitHub’s MCP server shows around 93 tools and approximately 55,000 tokens for definition before a single agent task is executed. A controlled benchmark by the Scalekit team ran 75 identical tasks through MCP and through a simple CLI with the same model. MCP used between 4 to 32 times more tokens per request than the CLI. One of the easiest tasks run by the CLI was measured at 1,365 tokens and the same task run through MCP was measured at 44,026 tokens. A couple of servers stacked together can easily consume a quarter to a half of the context window due to schema overhead. That’s roughly equivalent to a ‘hello world’ container that weighs 4 GB.

As with dependencies, there are costs beyond size. Researchers from Microsoft call this "tool-space interference". If agents get confused about tools of similar names (i.e. get_status, fetch_status, query_status, etc.) then overall quality of tool selection suffers. Context Rot work by Chroma illustrates this. For all of the major models they tested, large inputs negatively affected task performance. Overall, large tool surfaces makes agents slow, expensive and dumb. It should be treated like a dependency. The practices carry over almost directly.

Dependency habit

Agent-stack equivalent

Check bundle size before adding a package

Count schema tokens per request before connecting a server

Remove unused dependencies

Diff mounted tools against invoked tools, quarterly

Lazy-load what you rarely need

Deferred tool loading; skill triggers over full schemas

Keep build-time deps out of the runtime image

Subagent owns the heavy tool surface, returns a summary

The dependency playbook, translated.

Every server has a weight

With a merged dependency, we analyze what it brings in. We do the same with a server: what gets added? What is the cost of that server’s schemas with each request? Multiply that by the number of requests. A server that adds 50,000 tokens to an agent doing 10,000 requests a day is creating 500,000,000 tokens of standing overhead before any work is done. A server with good designs may be worth the overhead, but we should be intentional with the decision. I would give design review to anything that takes more than 10% of the context budget.

The corollary: select the narrowest interface that works. An agent trained on the CLI doesn’t need to learn schemas. The agent simply calls --help and moves on. The Scalekit benchmark evaluated a different approach: an 800-token usage note for the gh CLI, a small tips skill file. It reduced agent tool calls and latency by approximately a third when compared to using the bare CLI. Eight hundred tokens of skill and tips beats both the naïve and MCP schema approaches. For fairness to MCP, typed schemas result in fewer malformed calls compared to flag guessing. There is no CLI solution to remote auth, multi-tenancy and centralized policies. Every interface comes at a cost, and most teams never weigh the cost. The Practical Guide from the Coalition for Secure AI, Tool Design for Secure Agentic Systems, where I was a contributor, makes the same point from a security perspective: every exposed tool is a potential attack surface.

Most mounted tools never get called

Remove any dead/unused tools. Compare the tools that your agents invoke over a few weeks to the tools that are mounted. The diff takes about five minutes.

# Tools the agent CAN call
jq -r '.tools[].name' agent-config.json | sort -u > mounted.txt

 # Tools the agent DID call (last 30 days of traces)
jq -r 'select(.type == "tool_call") | .tool_name' traces/*.jsonl \
  | sort -u > invoked.txt

# Mounted but never invoked: candidates for removal
comm -23 mounted.txt invoked.txt

 I've never conducted an audit and not found things to eliminate. Embarrassing differences are usually seen when comparing best practice benchmarks to customer contacts. Our agents are shown hundreds of tools by our company and often times many more tools by our partners. The rest is usually unneeded overhead and due to the interference effect an active tax on the selection quality of tools used. A quarterly tool audit takes about an afternoon and, in my experience, removes about a third of the surface area of tools.

Lazy loading has come to agent tools

Packaging does lazy loading to combat bloat, and agent tooling does lazy loading as well. With MCP clients, older clients did an injection of the full schema up front. Newer clients enable tool searching. In lazy loading, the agent describes what it needs and the registry finds the correct tool and loads its definition in a context window. This is similar to skills. A skill description and a trigger are loaded in a context window. Skills are loaded and run only when their trigger is hit. This ensures that the standing cost of tools is converted to marginal cost. You only pay for a tool when you use it.

The cost of tool outputs also affects scalability. By default, tools output human readable/understandable text or parser output. This is expensive for models. This is more applicable to tools that produce repeated and lengthy outputs (e.g. the output of a tool execution status) that require just a few values. Use filtering methods to restrict your requests. Consider using tabular data representation for large and relatively uniform data to reduce token count. TOON can help reduce the token count by approximately 40% compared to JSON. In case of deeply nested and non-uniform data, or a combination of various data types (structures), TOON notes that JSON is better. If the tool output is large, send the output to a file and provide the agent with file path and a brief description, and do not put large output in the context window.

Heavy tool surfaces belong in a subagent

What does isolation look like here? Sometimes a subtask may require a heavyweight tool. In those cases, we may break the task up and give the subtask to a different subagent. There may also be cases where a planning agent owns a project tracker integration, makes a number of service calls within its scope, and synthesizes a compact summary to the main agent, which doesn't understand those schemas. This is a build time dependency that doesn't exist at runtime. This is usually a good match with a phase based workflow, where each phase begins with a small handoff record. The previous phase does not need to be propagated to the next phase.

Minimization can be shown as starving agents of context. In numerous cases, agents can fail because of a lack of state, and making certain that the right state gets to the right agents can be a hard problem. The emphasis is on defaults. Currently, the default is to be liberal in what we admit and hope for the best. However, with the dependency approach, we need to be conservative in what we admit and validate it.

Like the history of software packaging, the history of agent tooling is at a similar stage to software packaging before the major incidents of the late 2010s. Lockfiles, audit tools and bills of materials are the standard risk management tools, but like any tools, they changed the risk from an invisible risk to an auditable and manageable risk. This is the same with agent tooling surfaces. Right now, most are unmanaged and on by default. There are real world consequences to using these tooling surfaces. They have real world effects. They are already creating increased costs and they also contribute to security risks such as the registry poisoning risk I described in the CoSAI secure-AI tooling project. A number of teams are treating agent tooling as a managed dependency and running tools that are faster and cheaper. They are running the same models as everyone else. The difference is they have actually read their own context window and started saying no.