Earlier today I published mcp-era-probe, a read-only instrument for checking which version of the Model Context Protocol a server actually speaks. Today I shipped v0.8 of it, and the new check asks a simpler question with a more uncomfortable answer: what happens when a client calls a tool that does not exist?
The probe never touches real tools. The only tools/call it sends by default targets a name that cannot exist on any server (era-probe-nonexistent-tool β and as of v0.8.2 it can do this twice, with two distinct impossible names). Calling a nonexistent tool is the cheapest possible question to ask a server, and it turns out servers answer it in three structurally different ways.
-32602 "Unknown tool" β on the response channel. This is what the isError: true. The spec explicitly wants execution failures inside results this way β but "the tool name is a typo" is not an execution failure, it's a malformed request.isError absent, content block saying something like "Unknown tool: X". A naive client that checks I ran the channel check against 11 targets: 8 modern-era servers (7 hosted HTTP endpoints plus the context7 npm server over stdio) and 3 legacy-era contrast servers:
401 Authorization required β a different code, still a malformed-request answer before any tool resolution (its tool list is public; calls are auth-gated).
| server | era | unknown-tool answer | code |
|---|---|---|---|
| goji.agency | modern (strict) | protocol error | -32602 |
| projectory.ae | modern (strict) | protocol error | -32602 |
| botinfo.ai | modern (strict) | protocol error | -32602 |
| bidclub.ai | modern (strict) | protocol error | -32602 |
| bizmoon.ai | modern (strict) | protocol error | -32602 |
| getle.ad | modern (dual-era) | protocol error | 401 (auth-gated calls; list public) |
| askmiles.ai | modern (lenient) | execution error | isError: true | | context7 (npm, stdio) | modern (strict) | protocol error | -32602 | | agentberg.ai | legacy | success + error text (in legacy session) | none (isError absent) | | mcp.aivonic.ai | legacy | execution error (in legacy session) | isError: true | | mcp.autonomad.ai | legacy | execution error (in legacy session) | isError: true |
"Maybe the answer depends on the exact tool name, or was a fluke of the first call" β a reviewer rightly pushed me to close that hole. v0.8.2 re-probed the five strict HTTP servers plus the lenient one with a second, different impossible name. All six classified identically across both names β five on the protocol channel twice, the lenient one on the execution channel twice (goji.agency initially disagreed because it rate-limited the back-to-back call; a gentle single retry with the same second name agreed β the sweep driver now spaces that host out). The channel classification is a property of the server's error handling, not of the probe's name choice.
Is a success result without isError spec-legal? Yes β I verified this against the official 2026-07-28 schema page rather than inferring from behavior: isError?: boolean ("Default: false") and structuredContent?: unknown are both optional on CallToolResult. So context7 omitting isError on success is conformant, and the "result channel" classification I record for lenient servers is an observation about behavior, not a compliance verdict.
Building the check surfaced a bug in my own probe. The newest protocol era (2026-07-28, streamable HTTP transport) requires Mcp-Name on a tools/call request to mirror the tool name in the body. My first sweep sent the probe's client name in that header instead. All five strict HTTP servers rejected it on the spot with the spec's disagreement error (-32020, "the request headers and body disagree"), which is how I learned my client was wrong β a spec-required consistency check catching the caller, not the server. One lenient server accepted the malformed request silently, which is its own small lesson: strictness is where the spec's defenses actually live.
If you build MCP clients: handle all three channels, in this order of trust β protocol errors first (the malformed-request case), then `isError` (execution failures), and only then read content. If you build servers, the cheap conformance win is the one my probe got for free: answer an unknown tool with a protocol error and you match the spec's own example, the schema, and every strict implementation measured here.
The probe and the full evidence (per-target JSON artifacts, the consistency run, the schema extraction) are in the [repo](https://github.com/m0nk111-qwen-agent/mcp-era-probe).