Too Many Tools: Why Your MCP Server Shouldn't Expose Every Endpoint

Wrap a large API and you can end up with 180 MCP tools the model reads before it answers anything. Here's what that costs, what gets trimmed for you, and what only you can decide.

The first time you wrap a big API, the tool count is a little thrilling. You paste a spec, the platform reads it, and 180 tools appear. Every endpoint you own, ready for the model. Then you ask Claude to do something simple and it picks the wrong one.

That isn't a failure of the model or of the wrapping. It's a budget problem, and nobody warns you about it because the demo APIs in every tutorial have four endpoints. Wrap something real and the shape of the problem shows up immediately.

This post is about the part that comes after "it works": deciding which endpoints deserve to be tools. If you haven't wrapped anything yet, the no-code walkthrough is the better place to start, and the round trip explains how an operation becomes a tool in the first place.

What the model actually receives

When an MCP client connects, it calls tools/list and gets back every active tool: the name, the description, and the full JSON Schema for the inputs. That whole document goes into the model's context before it answers your first question, and it stays there.

So a tool isn't free. One endpoint with eight parameters and a nested request body serializes into a fair chunk of JSON Schema, and 180 of those add up to a document that competes with the actual conversation for room. You pay for it on every turn, whether or not the model calls anything.

The second cost is worse, because it doesn't show up on a bill. Choosing a tool is a retrieval problem, and the only thing the model retrieves against is your descriptions. Give it listOrders, listOrdersV2, getOrderHistory, searchOrders, and queryOrderIndex, all described in the same nine words your API team copied between operations, and the model is guessing. It picks one, calls it, gets something adjacent to what you wanted, then either tries again or confidently hands you the wrong answer. Twelve tools with sharp descriptions will beat a hundred with vague ones.

What gets trimmed before you see it

Some of the pruning happens during discovery, because a few categories are wrong for a model no matter what your API does.

Version duplicates collapse. Plenty of specs carry the same operation at /v1, /v2, and /v4, which is fine for HTTP clients and terrible for a model that now sees four tools with nearly identical names. Discovery groups operations by method plus a version-stripped path and keeps the highest version, so you get one clean tool instead of four numbered ones. When no path in the group carries a version, they're kept as distinct operations, because then they aren't duplicates.

Bulk and file operations default to off. An endpoint under a download, extract, or bulk path segment, or one whose only successful response is a zip, a PDF, a CSV, or an octet stream with no JSON alternative, returns a file rather than data the model can read. Those get flagged, switched off, and sorted last so the useful query tools surface first. There's a deliberate escape hatch: if every operation in a spec classifies that way, they all stay on, because a server with zero active tools looks broken and you deserve to see what's there.

Name collisions get resolved. MCP resolves tools/call by name, so two tools sharing one would mean the second is unreachable. Duplicates get a numeric suffix, trimmed to fit the 100-character cap.

That's the mechanical layer. It removes the things that are obviously wrong. It can't tell you which of your working endpoints an agent has any business calling.

What only you can decide

Three judgement calls are yours, and they're where most of the improvement lives.

Turn tools off. On the server's detail page every discovered tool has an active toggle, and the honest question for each one is whether you'd want an autonomous caller reaching it. Your admin endpoints, the health check, the migration trigger, the endpoint that exists solely because one legacy client still calls it: none of those help an agent answer a question, and several of them can ruin your afternoon. Switching a tool off leaves it discovered and documented. It just stops appearing in tools/list.

Write the descriptions for the model, not for your API docs. The description is the only thing the model reads to decide whether a tool applies, so "Returns order data" is a coin flip and "Returns line items, totals, and fulfillment status for a single order, given its order ID" is not. Descriptions carry over from your spec's summary and description fields and are truncated at 2000 characters, which is far more room than a good one needs.

Split servers by job instead of by API. One provider can back several MCP servers, and a server with twelve well-chosen tools aimed at one task will outperform one with a hundred and eighty aimed at everything. Give the support workflow its own server with the read endpoints it needs. Give the ops workflow a different one. Each client connects to the server that matches what it's for, and neither model wades through the other's tools.

Annotations help the human, not the server

Every tool also ships with MCP annotations derived from its HTTP method, following the 2025-06-18 spec. A GET is marked read-only and idempotent. DELETE and PUT are idempotent and destructive. PATCH is destructive but not idempotent. POST is neither, since a POST might create a record or might just be a search with a long body. openWorldHint is always true, because every tool here calls an external API.

Clients use these to decide what runs without asking you first. They're worth understanding for exactly what they are: hints that inform a confirmation prompt. The MCP spec is explicit that annotations from an untrusted server shouldn't be relied on for safety decisions, so they're a convenience for the person in the loop, not an access control. If an endpoint shouldn't be called, turn the tool off. Don't rely on a destructiveHint to save you.

Knowing it worked

You'll notice the difference in how the agent behaves, not in a metric. The exploratory calls stop, the first pick is right more often, and the answers stop being subtly about the wrong record.

The server test page is the fastest way to check: run a tool by hand, confirm it returns what you expect, and validate the ones you're unsure about before an agent finds them for you. The MCP servers documentation covers the toggles and the refresh behavior in more detail.

None of this is work you do once. Every time you refresh tools after a spec change, new operations arrive with their defaults, and the ones you disabled stay disabled. Ten minutes of curation after each refresh is the whole maintenance cost, and it buys you an agent that reaches for the right thing.

If you've already wrapped an API and the agent has been picking oddly, open the tool list and count how many of them you actually wanted it to have. That number is usually smaller than the one on the page. If you haven't wrapped anything yet, start free, wrap one, and turn off everything you wouldn't hand to a stranger with your credentials.