I asked my agent to close a stale GitHub issue.
It searched Notion. Twice. Then it called a Slack tool named search_messages, found nothing, apologized, and tried Notion again. The GitHub tool it needed was sitting right there in its tool list, four entries below the one it kept picking.
Nothing was broken. No server was down. The agent had 61 tools connected and it simply could not find the right one.
That was the day I stopped treating MCP servers like npm packages. Too many MCP tools is not a neutral cost you pay in tokens. It is an accuracy problem, and it shows up long before you hit any context limit.
TL;DR
- Every connected MCP tool lives in your system prompt on every single turn. 61 tools cost me roughly 11k tokens before the user even typed anything.
- The real damage isn't tokens, it's selection accuracy. Tool picking is a classification problem, and tools from different vendors have near-identical descriptions that collide.
- The failure mode is not "tool not found." It's a confident wrong call, a retry loop, and a context window full of junk results.
- In my own logs, first-call-correct rate went from ~92% at 12 tools to ~61% at 61 tools on the same task set.
- The fix is a tool budget: 10-15 tools per agent, scoped sub-agents, and wrappers that collapse a whole server into 2-3 verbs.
Why does adding more MCP tools make an AI agent worse?
Because tool selection is a classification task with a growing number of confusable classes, and nobody coordinated the labels.
Your model doesn't "browse" tools. It sees a flat list of JSON schemas in its system prompt and has to pick one in a single forward pass. Every tool you add makes that list longer, and worse, more likely to contain something that looks like the answer.
Here are three real descriptions that lived in my prompt at the same time:
search_issues(query) "Search issues in a repository"
search_pages(query) "Search across pages and databases"
search_messages(query) "Search messages matching a query"
Now read "find the ticket about the flaky auth test" and pick one, quickly, with no memory of which product the user means. The word "ticket" doesn't appear in any of them. All three take a single query string. All three are plausible.
The model isn't being stupid. It's being asked to disambiguate labels that three different vendors wrote independently, none of whom knew the others would be in the room.
What actually happens at 60+ tools?
Three things compound, and the third one is what kills you.
1. Fixed context tax. Tool definitions are not free and they are not cached away. Mine averaged ~180 tokens each once you count parameter schemas and enum values. Sixty-one tools was about 11k tokens of permanent overhead on every turn of a ten-turn agent loop.
2. Degraded selection. More candidates, more collisions. Descriptions written by different teams cluster in embedding space in ways nobody designed.
3. Retry pollution. This is the compounding one. A wrong tool call doesn't fail cleanly. It returns plausible garbage: an empty result set, a 404, a page of unrelated Notion blocks. That output goes into the context. Now the next turn has a longer prompt, a worse signal-to-noise ratio, and a model that is subtly anchored on the wrong product. Two bad calls in and the agent is reasoning about Notion when the answer was always in GitHub.
One misfire costs you the call. Three misfires cost you the session.
How many tools should an AI agent have?
My working number is 10-15 active tools per agent, hard ceiling around 20.
I got there by keeping a boring log. I ran the same 40 task prompts against my own harness at three tool counts and scored one thing: did the first tool call go to the right server?
| Active tools | First-call-correct | Avg calls per task |
|---|---|---|
| 12 | ~92% | 2.4 |
| 30 | ~78% | 3.6 |
| 61 | ~61% | 5.1 |
These are my numbers on my tasks with my prompts, not a published benchmark. Your curve will sit somewhere else. But the shape held every time I re-ran it, and the shape is the point: the cost of a tool is not linear, because each new tool can also break tools you already had working.
That last part deserves emphasis. Adding a Linear server made my GitHub tools worse. I did not touch the GitHub server. I just gave the model a second thing that also has "issues."
How do you fix MCP tool overload?
Four moves, roughly in order of payoff.
Delete first. Open your config. For every server, ask when you last actually used it in an agent loop. I killed four servers in ten minutes and lost nothing. This is the highest-leverage thing on the list and it takes no engineering.
Turn off tools, not just servers. Most servers ship 15-25 tools and you use three. A GitHub server gives you issue CRUD, PR CRUD, file reads, workflow runs, releases, gists. If your agent's job is triage, it needs search_issues, get_issue, comment. Allowlist those. Everything else is noise that competes for the same slot.
Scope by sub-agent. Instead of one agent with 61 tools, run a router that hands off to specialists: a code agent with the repo tools, a docs agent with Notion, a comms agent with Slack. Each sees 8-12 tools and a system prompt that already establishes the domain. Selection accuracy jumps because you removed the confusable classes before the model ever saw them, and each sub-agent's context stays clean.
Wrap instead of expose. My favorite. Write one thin tool with a verb-shaped name and fan out behind it:
# 12 raw MCP tools collapsed into one honest verb
def find_work_item(query: str, source: Literal["github", "linear"]):
"""Find a ticket, issue, or PR. Use for anything a human calls
a 'ticket', 'issue', 'bug', or 'task'."""
Two things happened when I did this. The prompt got shorter, obviously. But the bigger win was that I got to write the description myself, in the vocabulary my prompts actually use. Vendor descriptions describe the API. Your description should describe the intent.
Doesn't dynamic tool loading solve this?
Partly, and it's the right direction, but it isn't free.
Tool search or progressive disclosure, where the agent queries for relevant tools instead of holding all of them in the prompt, genuinely fixes the token tax and helps a lot with selection. If your runtime supports it, use it.
But you've now added a retrieval step, and retrieval can miss. When the model searches for "ticket" and your tool is described as "issue," you get the same failure with an extra round trip in front of it. Dynamic loading changes overload from a prompt problem into a search-quality problem. That's a much better problem to have. It isn't nothing.
The other trap: dynamic loading makes it painless to connect 200 tools, so people do. Then the retrieval layer is doing disambiguation over 200 vendor-written descriptions, and you're back where you started with more moving parts.
What should you actually do this week?
Log every tool call your agent makes with the task that triggered it. One JSONL line each. After a week, count how often the first call was right, and count how many tools you connected but never called once.
I'd bet money on what you'll find: a long tail of tools with zero calls that are quietly making your top ten worse.
So, do more MCP tools make your AI agent worse?
Yes, past roughly 20 active tools, and the damage is accuracy rather than cost. Tool definitions sit in the system prompt on every turn, so each one you add both eats context and adds another confusable option to a single-shot classification decision. Because vendors write tool descriptions independently, near-duplicate names like search_issues, search_pages, and search_messages collide, and a wrong pick returns plausible garbage that pollutes the context for the rest of the session. Keep 10-15 scoped tools per agent, allowlist individual tools instead of whole servers, split domains across sub-agents, and wrap chatty servers behind a few intent-shaped verbs you describe in your own vocabulary. A tool your agent never calls is not free optionality. It's a distractor you're paying for on every turn.
Top comments (0)