When an agentic pipeline starts picking the wrong tool, the usual advice is to move up to a bigger model. That costs money and rarely fixes anything. Look at your MCP tool descriptions first. Fourteen years of untangling other people’s integrations has taught me that no model, at any price, reads a messy schema the way you meant it.
Length bias: the longer description usually wins
Most people treat an MCP server as a black box. You connect it, list_tools returns a menu, and you assume the model reads that menu the way a developer would. It does not. Models such as GPT-4o and Gemini 2.0 lean toward the more complicated option: give Tool A three plain sentences and Tool B a paragraph stuffed with examples, and the agent reaches for Tool B even when Tool A is the correct call.
I ran into this on a WooCommerce integration where a plain “Get Order” tool sat unused because a “Generate Report” tool next to it had a fancier JSON schema. It is not a quirk you can ignore, and it means third-party MCP providers are effectively deciding where your model puts its attention. There is more on controlling that in my post on AI coding agent context.
Hiding arguments the model has no business filling in
The mistake I see most often is exposing internal state, things like user_id or session_token, as tool parameters. That is a security problem on its own, and it also asks the LLM to invent a value your application already has. So it spends tokens guessing a user ID that was never its concern.
Keep those parameters in the underlying function and out of what the model sees. Write your MCP tool descriptions for the arguments the model actually chooses, and a bloated schema tightens up fast:
{
"name": "bbioon_get_customer_data",
"description": "Retrieves purchase history. Use this when the user asks for their previous orders.",
"parameters": {
"type": "object",
"properties": {
"limit": {
"type": "integer",
"description": "Number of orders to return (default 5)."
},
"_user_id": {
"type": "string",
"description": "INTERNAL ONLY - DO NOT GENERATE"
}
},
"required": ["limit"]
}
}
Prefixing internal arguments, as with _user_id above, and stripping them from the prompt in a proxy leaves the model far less room to get it wrong. The server injects that ID; the prompt never mentions it.
Why a proxy layer is worth the extra hop
With more than one MCP server in play, do not wire them straight into the agent. Put something like Master-MCP in between. It lets you override MCP tool descriptions without touching the original server, which is the same reasoning behind filtering a plugin’s output instead of editing core.
A proxy also gives you logging and a place to orchestrate calls. You can see which description confused the model, adjust the wording, and watch whether accuracy moves. That is a tighter loop than swapping models every time a new mini or nano release lands. I go further into agent structure in mastering agentic AI with robust vibe agents.
If wrangling MCP schemas is eating your week, I take this on as contract work. I have been building on WordPress since the 4.x days and most of that time has gone into making external APIs behave.
Where to start
Read your tool list the way the model gets it and check whether one description is three times the length of its neighbors. Cut the arguments the model should never fill in. If you run several servers, put a proxy in front so you can change any of it without a pull request to someone else’s repository. The schema is the part you control.