菜单

发布前,怎么测你的 MCP server

2026-10-04MCP Checkup

在你告诉别人去加你的 MCP server 之前,最好先知道:agent 第一次连上来,看到的是什么。不是你的单元测试说你的处理函数怎么样,而是线上实际回来的东西:端点有没有应答,握手和它声称的协议修订对不对得上,工具清单客户端能不能解析,拒绝请求时回的是什么形状。

我们首页那个输入框回答的就是这些,贴上你的端点地址就行,不用注册账号。这篇文章讲它跑了什么、每项检查能说明什么,以及这份结果有哪三件事做不到。

先说三件事

结果不签名。 首页检查是一次即时观测,不属于任何目录页的历史,我们也不会给它签名。结果页上就是这么写的。这次检查留下什么、绝不会生成什么,另有一篇文章专门讲。

结果页 24 小时后过期。 首页按钮旁边写着这一点,结果页上也会印出它可访问到的具体时刻。过了这个时刻,链接的表现和一个不存在的页面一样。

需要基线的检查显示 UNVERIFIED。 有两项检查,是拿你现在的工具清单去和某个已批准的基线比较。首页的一次性检查没有基线,所以这两项都显示 UNVERIFIED,原因就印在那一行上:该 target 没有已批准基线。这是检查在告诉你「没法比较」,不是对你的 server 下的结论。

按下按钮之后发生什么

你贴一个 https:// 地址,探测器像客户端一样去连:不带凭据,只连你填的那个主机。一次首页检查最多发 8 个请求(server 分页返回工具列表时最多 17 个),10 秒后停止,每个响应最多读 2 MB。只有检查发出的那一个 GET(读取你的授权元数据)会跟随重定向,最多 3 跳。协议请求都是 POST,POST 绝不会重发到重定向的目标。首页检查也不会连你指定主机以外的任何主机。如果重定向或授权元数据指向别的主机,检查不会过去:被重定向的请求按它收到的那个应答记录,需要用到那台主机的检查会显示「未检查」并附上原因。

我们登记的每一项检查都会在结果页占一行,一共 15 行,不管它跑没跑成。没能运行的检查会被列出来,不会被悄悄丢掉。每一行最终落在四种状态之一,页面上写作「已通过」「未通过」「观察到风险」「未检查」。「未检查」就是我们站上其他地方说的 UNVERIFIED,并且总是附带原因。

有一个实际限制:我们对同一个主机最多每 10 分钟发起一次即时检查。如果你改了点东西又立刻再按一次,看到的是上一次的已记录观察(页面会标明),而不是一次新检查。改完,等一等,再查。

可达性与握手

reachability:我们和你的端点之间的握手交换以 HTTP 回应结束时,记「已通过」,状态码是什么都算。401 也算,毕竟有东西应答了。如果探测在交换结束前停下——你的端点要求我们稍后再来(429,或带 Retry-After 的 503)、某个回应超出大小上限、连接出错、或某项预算用尽——这一行记「未检查」并附上原因,即使你的端点已经答复过之前的请求。超时记「未检查」,而不是「未通过」,因为那也可能是我们这边的网络问题。

discovery_handshake 检查握手的行为是否符合所识别到的协议修订:现代的 server/discover,或者旧式的 initialize。protocol_revision 检查你说的那个修订我们是否认得。任何一项未通过,那一行会写明原因,比如没有声明修订,或者声明的修订我们不认识。它们都不能说明这个修订被完整实现了,只能说明你声称的握手,和实际应答的握手是同一个。

如果你的 server 有意把握手放在密钥后面,这几项会显示「未检查」,原因是 credential_required。我们从不发送凭据,看不到你的门后面,而这并不等于门坏了。我们怎么区分一次拒绝和一次失败里有细节。

工具清单

tools_list 请求你的工具列表,检查返回的结构。结构不合法记「未通过」,因为客户端同样会解析失败。它不能说明这些工具真的能用:我们从不调用它们。

error_taxonomy 确实调用了一样东西,而那是一个不存在的工具。探测器请求一个叫 __mcpcheckup_probe_nonexistent_tool__ 的工具,然后看你的拒绝是什么形状。格式合法的 JSON-RPC 错误记「已通过」。HTML 错误页、空响应体,或者一个只有 {"error": "nope"} 的 200,记「观察到风险」,因为客户端没有可靠的办法读懂它。单纯的 401 或 403 不算在你头上。如果你的工具列表是分页的,或者本来就有同名工具,这次调用不会发出,这一行记「未检查」。

tool_description_hygiene 读你的工具名和描述里的这些文字:agent 在决定调用什么之前会先读它们。它找的是零宽字符、Unicode 标签字符、双向控制字符、私用区字符、异常长的文字、对助手下指令而不是描述工具的句子、仿冒的系统标记、内嵌标记,以及非 ASCII 的工具名。命中记「观察到风险」,绝不记「未通过」。它只报告看到的信号,推断不了意图:一个真的在处理 Unicode 的工具,碰到其中几项是有正当理由的。

toolset_fingerprint 和 schema_fingerprint 对你的工具列表和每个输入结构计算指纹。这里的「已通过」只表示指纹算得出来,并不说明有没有变过。

连接的边缘

redirect_policy 把跨主机的重定向记为「观察到风险」,因为跟过去的 agent 会落到你可能没打算让它去的地方。它说明不了目的地好不好。如前所述,首页检查不会跟过去。

auth_metadata 看你的端点对匿名调用方给出的认证质询和元数据,判断结构是否合法。结构不合法记「观察到风险」。它说不出你的认证强不强:我们没有凭据,也从没见过真正的认证路径跑起来。

首页检查没看的部分

tls_certificate 在清单上,但目前我们的每一次运行都不检查它,首页检查和定期运行都一样,结果都是「未检查」。那一行会写明原因:校验证书链需要另一种执行器,而我们的探测器是基于 fetch 的。想检查证书,发布前请自己查一遍。

toolset_unchanged_vs_approved 和 schema_unchanged_vs_approved 就是前面说的两项基线检查。只有存在已批准基线时它们才会运行,而首页检查从来没有基线。

页面不会把这些行合成一个总结论。它只数出观测了几项、几项未检查;每一行保留自己的状态和原因。

一次检查还不够的时候

首页检查给你的是某一个时刻。server 会变:多一个工具,改一句描述,某个拒绝回应不再符合原来的形状。如果你想让同样的检查按计划反复运行,并且有一个留着历史的报告页,下一步是认领你的 server。你用一条 DNS 记录或一个我们让你提供的文件来证明自己掌控这个地址,我们从不索要凭据。认领会带来什么,一页就讲完了。