Debugging MCP: a field guide to 'tool not found' errors

Francisc Toth · APR 12, 2026 · 7 minutes
Debugging MCP: a field guide to 'tool not found' errors

"Tool not found" is the most common MCP error and the one with the worst error message. The cause can be on the client, the server, the transport, or the protocol layer. Here's how to figure out which.

The seven causes

In rough order of frequency:

  1. The server didn't register the tool.
  2. The client and server disagree on tool names.
  3. The transport disconnected and reconnected without re-handshaking.
  4. The tool exists but the schema is invalid.
  5. The model is calling a tool that was deprecated.
  6. Capability negotiation failed.
  7. The server crashed silently.

Each one has a specific signature. The trick is knowing which signature to look for.

Cause 1: Tool not registered

The most common case. You wrote a new tool, forgot to register it, restarted the server, the model can't find it.

Check the tools/list response. Most clients log this on connection. Claude Desktop puts it in ~/Library/Logs/Claude/mcp-server-<name>.log. The output is a JSON array of registered tools.

If your tool isn't in that list, the registration didn't happen. Common causes:

  • The tool is registered conditionally and the condition was false at startup.
  • The registration is in an async function that didn't complete before the server started accepting connections.
  • A typo in the tool name between the registration and the schema.

Add a log line that prints the tool list right after registration. If it's not there, the issue is in your registration code, not the protocol.

Cause 2: Name mismatch

The model calls query_database. The server has a tool called query-database. Different name. Same intent.

This happens when tool names get refactored without updating both ends. Sometimes the change happens in a system prompt or a tool description and isn't obvious from the diff.

To diagnose: dump the exact tools/call request the client sent. Most SDKs log this at debug level. Compare the name field to your server's registered tool names character-by-character. Pay attention to underscores vs hyphens, capitalization, and trailing whitespace.

Cause 3: Transport disconnect without re-handshake

This one's subtle. The TCP connection drops. The transport layer reconnects automatically. The client thinks it's still connected. But the server-side state, including the tool registry, was lost.

Symptom: the first tool call after a network blip fails with "tool not found." Subsequent calls work fine because the next tools/list re-discovers everything.

Fix: check that your client SDK re-runs capability negotiation on reconnect. The MCP spec requires it, but some early SDK versions skipped this step. Update your client SDK and test by manually dropping the connection.

Cause 4: Invalid schema

The tool registered, but its input schema failed validation when the client tried to load it. The client silently drops the tool from its registry. The model never sees it.

Look for warnings in the client log: "schema validation failed" or "skipping tool with invalid schema." The actual error is usually a Zod or JSON Schema validation failure, sometimes from a recent SDK update that tightened the schema spec.

The most common cause is a description field that's null instead of a string, or an enum with mixed types.

Cause 5: Deprecated tool

The model has the tool name in its context, maybe from a system prompt that wasn't updated, or from a memory of a previous conversation. The tool was renamed or removed.

Symptom: the model insists on calling a tool that doesn't exist. Even after error messages.

Fix: clear the model's context and start fresh. Update the system prompt if there's a hardcoded reference to the old tool name. If you've renamed a tool, leave the old name registered as an alias for a release cycle to give clients time to update.

Cause 6: Capability negotiation failed

The handshake at connection time exchanges capabilities: which protocol version, which features each side supports. If the negotiation fails, the connection succeeds but tools/list returns empty.

Look for the initialize response in the logs. Successful response contains capabilities.tools with at least an empty object. Failed response is missing the tools capability or returns an error.

Common causes: protocol version mismatch (client expects 2024-11, server speaks 2024-05), or a transport that swallowed the initialization request.

Cause 7: Server crashed silently

The server process exited but the client doesn't know yet. The connection appears alive at the TCP level, but any tool call returns "tool not found" because there's no process to handle it.

Symptom: every tool call fails identically. The error happens immediately, with no latency.

Fix: check the server logs for an exit. If you're running under a process manager (systemd, PM2, Kubernetes), check the restart count. A crash loop hidden behind auto-restart is the worst version of this. The server keeps coming back, registers no tools because something fails on startup, and crashes again.

A diagnostic checklist

When you hit "tool not found," work through this in order.

First, check if the tool appears in tools/list. If not, the problem is server-side registration (cause 1, 4, 7).

If it appears in tools/list but the model still says it's not found, check the actual call payload (cause 2).

If the call payload looks correct, check the connection state and capability negotiation logs (cause 3, 6).

If everything looks right but the model insists on calling a tool that doesn't exist, clear the context (cause 5).

Most "tool not found" debugging sessions end in causes 1, 2, or 7. Start there.

How Toolcall surfaces this

We surface the registered tool list, the most recent tools/call payload, and the capability negotiation result in the dashboard for every connected client. Most of the diagnostic steps above are visible without touching logs.

For self-hosted setups, the principles are the same. Log loudly at startup. Make the tool registration visible. Treat capability negotiation as a hard error if it fails.

The protocol is small enough to debug end-to-end. The trick is knowing where to look.

Debugging MCP: a field guide to 'tool not found' errors

Francisc Toth · APR 12, 2026 · 7 minutes
Debugging MCP: a field guide to 'tool not found' errors

"Tool not found" is the most common MCP error and the one with the worst error message. The cause can be on the client, the server, the transport, or the protocol layer. Here's how to figure out which.

The seven causes

In rough order of frequency:

  1. The server didn't register the tool.
  2. The client and server disagree on tool names.
  3. The transport disconnected and reconnected without re-handshaking.
  4. The tool exists but the schema is invalid.
  5. The model is calling a tool that was deprecated.
  6. Capability negotiation failed.
  7. The server crashed silently.

Each one has a specific signature. The trick is knowing which signature to look for.

Cause 1: Tool not registered

The most common case. You wrote a new tool, forgot to register it, restarted the server, the model can't find it.

Check the tools/list response. Most clients log this on connection. Claude Desktop puts it in ~/Library/Logs/Claude/mcp-server-<name>.log. The output is a JSON array of registered tools.

If your tool isn't in that list, the registration didn't happen. Common causes:

  • The tool is registered conditionally and the condition was false at startup.
  • The registration is in an async function that didn't complete before the server started accepting connections.
  • A typo in the tool name between the registration and the schema.

Add a log line that prints the tool list right after registration. If it's not there, the issue is in your registration code, not the protocol.

Cause 2: Name mismatch

The model calls query_database. The server has a tool called query-database. Different name. Same intent.

This happens when tool names get refactored without updating both ends. Sometimes the change happens in a system prompt or a tool description and isn't obvious from the diff.

To diagnose: dump the exact tools/call request the client sent. Most SDKs log this at debug level. Compare the name field to your server's registered tool names character-by-character. Pay attention to underscores vs hyphens, capitalization, and trailing whitespace.

Cause 3: Transport disconnect without re-handshake

This one's subtle. The TCP connection drops. The transport layer reconnects automatically. The client thinks it's still connected. But the server-side state, including the tool registry, was lost.

Symptom: the first tool call after a network blip fails with "tool not found." Subsequent calls work fine because the next tools/list re-discovers everything.

Fix: check that your client SDK re-runs capability negotiation on reconnect. The MCP spec requires it, but some early SDK versions skipped this step. Update your client SDK and test by manually dropping the connection.

Cause 4: Invalid schema

The tool registered, but its input schema failed validation when the client tried to load it. The client silently drops the tool from its registry. The model never sees it.

Look for warnings in the client log: "schema validation failed" or "skipping tool with invalid schema." The actual error is usually a Zod or JSON Schema validation failure, sometimes from a recent SDK update that tightened the schema spec.

The most common cause is a description field that's null instead of a string, or an enum with mixed types.

Cause 5: Deprecated tool

The model has the tool name in its context, maybe from a system prompt that wasn't updated, or from a memory of a previous conversation. The tool was renamed or removed.

Symptom: the model insists on calling a tool that doesn't exist. Even after error messages.

Fix: clear the model's context and start fresh. Update the system prompt if there's a hardcoded reference to the old tool name. If you've renamed a tool, leave the old name registered as an alias for a release cycle to give clients time to update.

Cause 6: Capability negotiation failed

The handshake at connection time exchanges capabilities: which protocol version, which features each side supports. If the negotiation fails, the connection succeeds but tools/list returns empty.

Look for the initialize response in the logs. Successful response contains capabilities.tools with at least an empty object. Failed response is missing the tools capability or returns an error.

Common causes: protocol version mismatch (client expects 2024-11, server speaks 2024-05), or a transport that swallowed the initialization request.

Cause 7: Server crashed silently

The server process exited but the client doesn't know yet. The connection appears alive at the TCP level, but any tool call returns "tool not found" because there's no process to handle it.

Symptom: every tool call fails identically. The error happens immediately, with no latency.

Fix: check the server logs for an exit. If you're running under a process manager (systemd, PM2, Kubernetes), check the restart count. A crash loop hidden behind auto-restart is the worst version of this. The server keeps coming back, registers no tools because something fails on startup, and crashes again.

A diagnostic checklist

When you hit "tool not found," work through this in order.

First, check if the tool appears in tools/list. If not, the problem is server-side registration (cause 1, 4, 7).

If it appears in tools/list but the model still says it's not found, check the actual call payload (cause 2).

If the call payload looks correct, check the connection state and capability negotiation logs (cause 3, 6).

If everything looks right but the model insists on calling a tool that doesn't exist, clear the context (cause 5).

Most "tool not found" debugging sessions end in causes 1, 2, or 7. Start there.

How Toolcall surfaces this

We surface the registered tool list, the most recent tools/call payload, and the capability negotiation result in the dashboard for every connected client. Most of the diagnostic steps above are visible without touching logs.

For self-hosted setups, the principles are the same. Log loudly at startup. Make the tool registration visible. Treat capability negotiation as a hard error if it fails.

The protocol is small enough to debug end-to-end. The trick is knowing where to look.

// READY TO SHIP

START YOUR FIRST MCP SERVER
IN UNDER FIVE MINUTES

No credit card required. Hobby plan is free forever.

Create a free website with Framer, the website builder loved by startups, designers and agencies.