菜单

调用不存在的工具:该回 JSON-RPC 错误,而不是 isError

2026-10-25MCP Checkup

10 月 25 日,一个公开 MCP server 的维护者给我们写了信。他们的报告上有一项观察到的风险:error_taxonomy。信里说代码已经改好了:调用一个不存在的工具,现在会收到 code 为 -32602 的 JSON-RPC 错误,并附上可用工具的列表。改动随他们下一次部署上线,之后我们的第一轮检测就会把结果记下来。

这正是我们做报告的用意:我们公布观察到的情况,维护者读了报告去改,下一轮签名检测记下变化。这项检查背后的问题其实很常见,下面说说它查什么、自己怎么测。

这项检查发什么

每轮检测在握手和 tools/list 之后,探测器会调用一个任何 server 都不该有的工具名:

{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"__mcpcheckup_probe_nonexistent_tool__","arguments":{}}}

回复是格式正确的 JSON-RPC 错误对象(不论 code 是多少),这项检查就记为 VERIFIED。回复是其他任何东西,就记为 OBSERVED_RISK,其中最常见的是一个普通的 result,里面带 isError: true。401 或 403 两边都不算:请求在到达工具分发之前就被拒了,所以这项检查记为 UNVERIFIED。

区别在哪里

MCP 规范的 tools 一节把失败分成两类:

  • 协议错误:请求本身无法处理,比如调用的工具 server 根本没有。这类要回 JSON-RPC 错误。规范里未知工具的示例用的是 -32602。
  • 工具执行错误:工具跑了但失败了,比如上游 API 超时。这类放在普通 result 里,带 isError: true,让模型读到报错后换个办法。

未知工具名属于协议错误,因为根本没有工具运行。用 isError: true 回答,等于告诉客户端「有一个叫这个名字的工具,它失败了」。如果客户端对两种情况的处理不同,比如工具失败时重试,遇到协议错误时刷新工具列表,就会走错路。

测一测自己的 server

先建立会话(Streamable HTTP,协议版本 2025-11-25):

URL=https://your-server.example/mcp
curl -sS -D - "$URL" \
  -H 'content-type: application/json' \
  -H 'accept: application/json, text/event-stream' \
  -H 'mcp-protocol-version: 2025-11-25' \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"error-taxonomy-test","version":"1"}}}'

如果响应里有 Mcp-Session-Id 头,下一个请求把它原样带上。然后调用一个不存在的工具:

curl -sS "$URL" \
  -H 'content-type: application/json' \
  -H 'accept: application/json, text/event-stream' \
  -H 'mcp-protocol-version: 2025-11-25' \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"no_such_tool","arguments":{}}}'

符合规范的回答带 error:

{"jsonrpc":"2.0","id":2,"error":{"code":-32602,"message":"Unknown tool: no_such_tool"}}

我们最常见到的却是这样:

{"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":"Tool no_such_tool not found"}],"isError":true}}

改在哪里取决于你的技术栈。手写的分发逻辑里,通常就是按工具名查找的那个分支:在那里直接返回 JSON-RPC 错误,不要构造 result。有些框架会把工具处理函数抛出的所有异常都包成 isError,「找不到工具」也不例外。如果你用的框架是这样,看看新版本是不是已经对未知工具回协议错误。

这个问题有多常见

下面统计的是每个被追踪的 server 过去三天里最新的一轮检测:共 5,525 个 server,读取时间 2026 年 10 月 25 日 13:26 UTC。

error_taxonomy server 数
VERIFIED 1,850
OBSERVED_RISK 1,459
UNVERIFIED 2,216

1,459 个观察到的风险里:

  • 1,411 个是带 isError: true 的普通 result;
  • 29 个是不带 isError 的 result,就像调用成功了一样;
  • 19 个回复根本不是有效的 JSON-RPC 消息。

UNVERIFIED 的大多是在工具分发之前就要求凭据的 server,而我们的探测器从不携带凭据。

也就是说,在能跑这项检查的 3,309 个 server 里,有 44% 记录了这项风险。和 MCP Checkup 上的每一项检查一样,它单独列出,从不和其他检查合成一个数字。我们记录的七种回答,以及第一次统计时的分布,见我们向 1,144 台 MCP server 调用了一个编造的工具。

看看你自己的 server

在 mcpcheckup.com/servers 搜你的 server,或者让接入了 MCP Checkup 的 agent 对它调用 get_mcp_report。每项检查都会显示状态,观察到的风险还会写明收到了什么。部署修复之后,下一轮定时检测就会记下新状态。认领你的 server 之后,检测会更频繁,检查失败时你会收到邮件。