What Actually Happens When One MCP Server Has 200 Tools
"How do you handle a 200-tool MCP server without blowing the context window" has become a recurring question in the MCP community, and for good reason: at roughly 400-500 tokens per tool definition, a server that size costs 80,000-100,000 tokens before anyone has typed a word. GitHub's MCP server alone runs about 35 tools at ~26,000 tokens. Most clients start degrading well before 200.
We went through our own codebase and checked, tool by tool, what we actually solve for this today versus what's still a real gap. Not a feature list - an audit.
What's actually solved
Namespacing, with automatic collision-safe hashing. Every tool from
every upstream gets prefixed namespace__toolname by default. When that
combination would exceed a client's name-length limit (64 characters by
default), it falls back to a deterministic SHA-256 hash instead, storing
the original name in _meta for debugging. This isn't a nice-to-have -
plenty of MCP clients silently choke or truncate on long tool names once
you're aggregating several servers' worth of tools under one endpoint.
Static per-tool allowlisting within a single server. If one upstream
genuinely exposes 200 tools and you only need twelve of them, permissions
support exact names, wildcards, and regex against allowedTools per MCP
entry. Set it once per credential/subscription and only those tools ever
reach the client - the other 188 never enter the tool list at all. This
is the direct, if manual, answer to "I have one huge server and want a
small slice of it."
Dynamic, task-based activation across a bundle. This is the more
interesting piece. The LLM Tool Router can expose a single meta-tool,
bundler__set_context, that takes a one-sentence description of the
current task. On each call, it re-ranks every upstream server in the
bundle against that description and attaches only the top N - everything
else is filtered out of tools/list entirely, not just hidden in the UI.
There's also a passive mode: a rolling window that re-ranks automatically
every few tool calls based on recent call history, no explicit
set_context call required. If the ranking LLM call fails outright
(network error, provider outage), it fails open - attaching available
upstreams up to the max rather than leaving a session with zero tools.
Put together: namespacing keeps 200 tools from colliding or breaking clients, static allowlisting lets you hand-curate a big server down to what you need, and the router dynamically decides which servers in a bundle are relevant to the task at hand.
Where it actually falls short
Here's the part that doesn't make it into feature lists.
The router's unit of selection is the whole server, not the individual tool. If your 200 tools live on one upstream MCP server - not spread across many bundled servers - the LLM Tool Router provides zero help. There's only one namespace to activate or not; it's all 200 tools or none. The router was built to decide which servers in a bundle matter right now, not to reach inside one large server and dynamically surface just the relevant dozen tools for this task. Today, the only lever for that specific scenario is the static allowlist above - which works, but requires knowing in advance which tools you need rather than adapting automatically per task the way the router does across servers.
There's no tool-level discovery meta-tool. set_context works from a
task description; there's no search_tools-style call that lets an agent
browse or query the available tool catalog by category or keyword before
committing to a task description. For a genuinely huge, heterogeneous
bundle, category-based discovery would be a meaningfully different (and
in some cases better) interaction model than "describe your task and
hope the ranker gets it right."
Both of these are real, specific gaps, not hedging. We're putting
per-tool dynamic routing within a single large server - extending the
router's unit of selection below the namespace level - on the roadmap,
along with a category/discovery meta-tool as a complement to
set_context. Neither is solved today; both are going on the roadmap
rather than getting glossed over in a features table.
The honest summary
| Problem | Status |
|---|---|
| Tool names colliding or exceeding client limits | Solved - namespacing + hashing |
| One big server, need a fixed known subset | Solved - static per-tool allowlist |
| Many bundled servers, need the relevant ones per task | Solved - LLM Tool Router |
| One big server, need a dynamic per-task subset | Not solved - roadmap |
| Browsing/searching the tool catalog by category | Not solved - roadmap |
If you're dealing with the single-huge-server version of this problem today, the static allowlist is the honest answer, not the router - use it, and expect the dynamic version to close that gap.