Troubleshooting
Your MCP server connects and the tools still do not run
The server is green, the tool count is right, and the model answers without touching any of it. That is a selection problem, not a connection problem: ten causes with distinct fingerprints, from a six-word description to the thirtieth tool that pushed the right one out of reach.
The server is connected. /mcp shows it green with a tool count next to it, and you can read the tool names in the panel. Then you ask for the thing that tool exists to do, and the model writes you a paragraph, or greps a file, or apologises — and never calls it.
This is not the same bug as a server that never appears, which has its own fix list in why your MCP server isn't showing up in Claude Code. Everything that article covers has already gone right: config, transport, scope, startup, enumeration. You are stuck on a different question — not "can the client reach the server" but "will the model choose the tool".
That question has about ten answers, each with a different fingerprint.
Connected is a fact about the client, not about the model
A connected server means the client completed a handshake and received a tool list. The count in /mcp tells you the client holds the definitions — not whether they reached the model, whether the model can tell them apart, or whether calling one is permitted.
Tool calling is the model's decision, by design: "Tools in MCP are designed to be model-controlled, meaning that the language model can discover and invoke tools automatically based on its contextual understanding and the user's prompts." Nothing in the protocol makes a tool fire. The server offers; the model chooses. So the question becomes: what did the model see, and what did it read there?
Check whether the tool is in front of the model at all
Rule out the three ways a listed tool is not in the model's context.
It is deferred. Tool search is on by default in Claude Code and it changes what loads: "Only tool names and server instructions load at session start, so adding more MCP servers has minimal impact on your context window." Definitions arrive when the model searches for them; for the handful that must be visible every turn, "set alwaysLoad to true in that server's configuration".
It was denied, and denial is not a prompt. A deny rule does not block the call when it happens: "A bare tool name like Bash removes the tool from Claude's context entirely, so Claude never sees it." The same applies to mcp__* patterns. The model is not refusing your tool; it does not have one.
Your organisation blocked it. On a managed machine, a connector tool set to blocked is filtered out before Claude sees it and never appears in the tool list.
The test that separates these from everything downstream: ask the model, in the session, to list the tools it has from that server. If it names the tool, your problem is selection. If not, it is availability, and no prompt rewriting will help.
The description is the only thing the model reads
This is the cause underneath most of the others: the model does not see your README, your source, or your intention. It sees a name, a description and a schema.
Anthropic's documentation is direct about the consequence — "Claude determines when to call a tool based on the user's request and the tool's description" — and the guidance that follows is stronger than most people write to: "Provide extremely detailed descriptions. This is by far the most important factor in tool performance." The recommended length is not a phrase: "Aim for at least 3–4 sentences for each tool description, more if the tool is complex", covering what it does, when it should and should not be used, and what each parameter means.
Now look at yours. Most MCP tools in the wild carry something like "Query the database" — six words describing the implementation, answering neither question the model is asking: is this the right moment and what will I get back.
The fingerprint: the tool fires reliably when you name it (use the query_metrics tool) and never when you describe the task. Naming it bypasses selection, so that is a diagnosis, not a fix. And there is a length trap at the other end — Claude Code "truncates tool descriptions and server instructions at 2KB each. Keep them concise to avoid truncation, and put critical details near the start."
Your words and the description's words do not overlap
A subtler version of the same problem — retrieval rather than judgement. With tool search, the model finds tools by searching a catalogue: "Claude searches your tool catalog (including tool names, descriptions, argument names, and argument descriptions) and loads only the tools it needs." Search matches text, so a description reading Retrieves telemetry records from the observability store gives "why was the site slow yesterday" nothing to land on.
The fix is a writing instruction, not a config change: "Use keywords in descriptions that match how users describe tasks." Put the words your team actually types — slow, latency, error rate, outage — into the description. The fingerprint: rewording your request makes the tool appear, which puts the gap in the description, not the model.
Thirty tools in, selection starts to slip
Tools compete: adding a server adds candidates the right tool has to beat. Anthropic publishes a number for where this starts to hurt: "Claude's ability to pick the right tool degrades once you exceed 30–50 available tools." Three or four mid-sized MCP servers put you there. The symptom is not a hard failure — it is a tool that used to fire reliably and now fires most of the time, dated to the day you added an unrelated server.
Two counter-measures: prune servers you are not using in this project, and consolidate — "Fewer, more capable tools reduce selection ambiguity and make your tool surface easier for Claude to navigate" — which is worth passing upstream to a server exposing forty near-identical endpoints.
The name collides with something the model already has
Names are load-bearing, because the model reads them as evidence before it reads the description. The specification only requires that "Tool names SHOULD be unique within a server" — within, not across. Uniqueness across a session is the client's problem, which is why Claude Code namespaces MCP tools as mcp__<server>__<tool>. That prevents a hard collision, not a semantic one: a tool called search or read competes with built-ins the model has used thousands of times.
Hence "Use meaningful namespacing in tool names" — prefix by service, so linear_search_issues rather than search. The fingerprint is easy to miss in a transcript: the model calls the similarly-named built-in instead, appears to succeed, and nothing errors.
The model had a cheaper answer and took it
Sometimes the tool is visible, well described and uniquely named, and the model still does not call it, because it already had an answer it considered good enough. This is the most under-diagnosed cause on the list. A coding agent that can read files will read a schema file rather than query your database server; a model with plausible general knowledge about your framework will answer from it rather than call your docs server. Both are reasonable from its side: an answer without a round trip.
The fingerprint is content, not behaviour. The answer arrives fast, sounds confident, and is subtly stale — the version number a year old, the column list missing the one you added last week. Where you control the request, the lever is forcing the choice: "In some cases, you may want Claude to use a specific tool to answer the user's question, even if Claude would otherwise answer directly without calling a tool" — which is what tool_choice is for. In a chat client, name the tool in the message. If that works you have confirmed the cause, not fixed it: put the when into the description.
It needs an argument the model cannot invent
A tool whose required parameters cannot be inferred from the conversation is one the model will quietly skip, or call wrongly. If get_report requires a workspace_id that appears nowhere in the session and has no default, the model can guess, ask, or route around; smaller models lean towards guessing — "Use Claude Haiku models for straightforward tools, but note they may infer missing parameters." The fix is on the server: give the parameter a default, add a companion list_workspaces tool, or say in the schema where the value comes from.
There is a hard version of this too. Some servers declare a tool's input schema as a JSON Schema union, "with anyOf, oneOf, or allOf at the top level of the schema. The Claude API doesn't accept those keywords at the schema root." Claude Code normally rewrites those, but when it cannot, "it skips that one tool, records the reason in the server's log, and leaves the server's other tools available." Memorise that fingerprint: one tool missing while its siblings work. The log has the reason; the panel does not.
It failed once, and the model stopped trying
Within a session, a tool that errors is evidence. The model saw a call fail and its next plan reflects that — it will often solve the problem another way rather than retry, which is sensible and looks exactly like the tool being ignored. The fingerprint is temporal: the tool worked early in the session and has not been touched since. Nothing in your config changed; the change was in the conversation.
Find the first failed call — that error, not the current silence, is the bug — and retest in a new session, because one that has learned to avoid the tool is not a clean measurement.
Annotations describe the tool; they do not compel the client
Server authors reach for annotations when a tool is not being called, on the theory that marking it read-only makes it safer to invoke and so likelier to run. It does not. Annotations are "Optional properties describing tool behavior", and the specification is explicit about their weight: "For trust & safety and security, clients MUST consider tool annotations to be untrusted unless they come from trusted servers." A client may ignore every hint you set. They shape how a call is presented, not whether it is chosen — and the one annotation that reliably changes behaviour runs the other way, requiring explicit approval on every call.
The order to check these in
Each step eliminates a cause or points at one, and the cheap ones invalidate the expensive ones.
- Ask the model to list the tools it has from that server. Not named? It is availability — deferral, a deny rule, or an organisation block. Stop here.
- Name the tool explicitly. If it now fires, your problem is selection; if it errors, read the error.
- Read the description as the model would. Six words is a bug; three to four sentences saying when to use it and when not to is the target.
- Check vocabulary overlap between that description and what you actually typed.
- Count your loaded tools. Past thirty, prune servers before tuning anything.
- Search the transcript for what was called — often a similarly-named built-in.
- Find the first failed call, then retest in a fresh session.
- If one tool is missing while its siblings work, read the server's log.
Steps 1 and 2 take a minute between them and split the problem in half, which is why they are first.
Practise this topic
Reading about it is half of it. Answer some questions on the same material — scored instantly, explanation for every one, no login.
Sources
- Tools — Model Context Protocol, accessed 2026-08-23
- Tool use with Claude — Anthropic, accessed 2026-08-23
- Define tools — Anthropic, accessed 2026-08-23
- Tool search tool — Anthropic, accessed 2026-08-23
- Configure permissions — Anthropic, accessed 2026-08-23
- Connect Claude Code to tools via MCP — Anthropic, accessed 2026-08-23
Rohan Surve is a Technical Product Manager in Bengaluru with 12 years in enterprise delivery and 0→1 product building. He works with Claude, Claude Code, Cursor and MCP daily, and built PrepMint after noticing how much of what he "knew" about these tools was half-remembered from documentation he'd skimmed once. Every question here is written from working with the tool and checked against the vendor's own docs.