11.9 万份签名的 MCP server 检测结果:在线情况与工具列表漂移
英文版更新于 2026 年 10 月 22 日,这是它的中文译本,数据截至 10 月 21 日。之后有一处变化:10 月 22 日起,探测器会读完 tools/list 的全部分页。下文「只读第一页」的说法,指的是截止时的情况。
从 2026 年 8 月 20 日起,我们按固定排期探测公开的远程 MCP server,不带任何凭据;从 8 月 22 日起,对观察到的结果签名。这篇汇总截至 2026 年 10 月 21 日 23:00 UTC 的数据。每个数字都来自对我们生产数据库的只读查询,并在出现的地方说明口径。
这些数据我们不合成任何分数,也都不是对某个 server 的结论。它们是观察结果,以及得出这些观察时的条件。
数据集
截止时,探测列表里有 5,916 个远程 MCP endpoint。它们不都签了名,也不都被观察了整整一个月。对每个 endpoint,我们取截止前 7 天内最近的一轮检测,5,912 个有这样的一轮。
| 最近一轮 | endpoint 数 | 占比 |
|---|---|---|
| 已签名,完整覆盖 | 3,564 | 60.3% |
| 已签名,部分覆盖(需登录) | 1,898 | 32.1% |
| 未签名 | 450 | 7.6% |
450 个未签名的检测里:
- 412 个没有完成 MCP 握手;
- 36 个完成了握手,但没返回能做指纹的工具列表;
- 2 个被我们的出站网络防护拦下。
统计在线情况至少要 7 天的观察。951 个 endpoint 不够 7 天,大多是 10 月才加进来的,所以在线情况一节覆盖 4,961 个。
针对这些 endpoint,我们存有 194,352 轮探测,第一轮在 8 月 20 日。其中 119,510 轮带签名的证明:114,398 轮是完整覆盖,5,112 轮是需登录覆盖(10 月 20 日起才有)。这 119,510 轮里有一轮是 8 月 20 日的测试,用的是开发密钥签名,那把密钥不在我们公布的密钥列表里,所以我们的验证器会拒绝它。
「完整覆盖」的意思是每项检查都尝试过了,不是每项都有结论。一轮典型的完整覆盖检测,在我们 15 项检查里对 10 项给出结论,另外 5 项记为 UNVERIFIED 并写明原因:
- TLS 和延迟检查,当时还没有开始运行;
- 鉴权元数据,server 没出示登录质询的时候;
- 和已批准基线对比的两项,还没有基线的时候。
我们首页的统计口径不一样:
- 目录里的 server(10 月 22 日 00:23 UTC 查时是 3,770 个)只算至少返回过一次工具列表的 server。本文统计探测列表上的每个 endpoint,包括先要求登录的、从没完成过握手的。
- 检测次数和签名结果是累计总数,包括已按保留策略删掉的检测。
- **「近 30 天工具集有变化」**只比较工具名,范围是所有列出的 server。
- 协议面板统计最近一次结果为完整覆盖签名的 3,564 个 server;本文统计完成握手的 3,602 个。
签名能说明什么、不能说明什么
签名表明这条记录是我们发出的,并且之后没被改动过。它不表明 server 好不好,不表明它明天还会这样,也说明不了登录后面有什么。详见一份签名证明能证明什么。
在线情况:server 多常应答
我们按 UTC 日来看每个 server。
- 在线: 当天每一轮检测都连上了 server。
- 不在线: 有一轮检测发现 server 没应答:域名解析不出来、连接失败、在时间预算内没收到完整响应,或者握手拿到了 HTTP 5xx。
- 不计入: 只有我们的探测器得不出结论的日子,比如被限流了。
一个 server 的比率,是在线天数除以计入的天数。
这段时间里规则有过调整:握手时的 HTTP 5xx 从 9 月 23 日起算作不在线,连接失败从 9 月 27 日起算作不在线。在那之前,这样的一天可能被算作在线,也可能不计入,所以窗口的开头会稍微偏向「在线」。
我们用 9 月 22 日到 10 月 20 日这 29 个完整的 UTC 日,其间有 4,961 个 server 至少有 7 个计入的天。9 月 21 日没有算进来:那天有 81 个 server 被记为没应答,前后几天只有 7 到 22 个。那天我们部署了三次探测器,而那天的检测记录已经按保留策略删掉了,所以说不清原因是不是在我们这边。如果把 9 月 21 日算进来,每个计入日都应答的 server 占比会从 89.4% 降到 88.3%。
| 分组(按最近一轮) | server 数 | 100% | 95–99% | 80–94% | 50–79% | 低于 50% |
|---|---|---|---|---|---|---|
| 已签名,完整覆盖 | 2,967 | 2,692(90.7%) | 118 | 130 | 21 | 6 |
| 已签名,需登录 | 1,593 | 1,485(93.2%) | 63 | 41 | 4 | 0 |
| 最近一轮未签名 | 401 | 258(64.3%) | 16 | 33 | 39 | 55 |
| 全部 | 4,961 | 4,435(89.4%) | 197 | 204 | 64 | 61 |
比率先四舍五入到整数百分比,再分档。
大多数 server 在每个计入的日子都应答了。要求登录的 server 比开放的稍好一点;对它们来说,「应答」指的是返回了 401 质询,登录后面的服务是否正常,我们看不到。长尾几乎全在最近一轮未签名的 server 里:低于 50% 的 61 个里,有 55 个在这一组。这里面有一部分是选择效应,因为最近一轮失败的 server,本来就是最近出过状况的。
未认领的 server 每 12 小时探测一次,所以一天通常只有两轮检测,两轮之间的短暂中断看不到。这衡量的是客户端来的时候 server 多半在不在,不是分钟级的可用性。
漂移:工具列表多常变
每一轮拿到工具列表的检测,都会和同一个 server 的上一份列表比较。每个工具的名字、描述和输入 schema 都参与比较。排除条件和我们之前那篇MCP 工具集多久变一次相同:
- 包含: 窗口开始时已经存有工具列表、并且窗口期间我们至少真正读到过一次工具列表的 server;
- 排除: 3 个已认领的 server(我们读它们的频率高于每 12 小时一次),以及 7 个返回分页工具列表的 server。
| 窗口 | server 数 | 有任何变化 | 增减了工具 | schema 变了、名字没变 | 只改了描述 | 可能造成破坏 |
|---|---|---|---|---|---|---|
| 7 天(10 月 14–21 日) | 3,029 | 780(25.8%) | 376(12.4%) | 234(7.7%) | 170(5.6%) | 115(3.8%) |
| 30 天(9 月 21 日–10 月 21 日) | 815 | 398(48.8%) | 261(32.0%) | 91(11.2%) | 46(5.6%) | 115(14.1%) |
中间三列互斥,每个 server 只出现一次,放在第一个符合的列里。
可能造成破坏的意思是,窗口里至少有一次变化出现了下面任一情况:
- 有工具消失了;
- 留下的工具删掉了某个参数;
- 某个参数声明的
type变了; - 某个参数新变成了
required。
这些变化都可能让原本有效的调用失败。会不会真失败,取决于客户端和 server 的校验,所以这是上限,不是失败次数。
任意一周里,这些 server 大约四分之一有某种变化,大约八分之一增减了工具。过去五周这两个比例很稳定,任何变化在 26% 到 29% 之间,增减工具在 12% 到 14% 之间;同期统计的 server 从 171 个增加到了 3,029 个。
把这 30 天里我们读过的所有 server 都算上(不只上面的 815 个,已认领和分页的仍然排除):
- 变化扎堆。 1,509 个 server 共存了 5,054 份变化后的列表。98 个 server 变了 10 次以上,占全部变化的 29%。
- 很少变回去。 只有 41 份变化后的列表和同一个 server 更早的某份列表完全一样。
- 描述变得最多,但很少单独变。 我们统计到 12,951 次单个工具的描述变化,对比之下新增工具 6,754 个、删除 2,500 个、schema 变化 9,154 次。764 次描述变化只差在数字上,比如数量、日期或版本号;31 次只差在空白字符。可在任一窗口里,只改描述的 server 只占 5.6%。
- type 的变化大多是精度问题。 最常见的 type 变化是
number改成integer:13 个 server 上有 319 处参数变化,大部分来自同一个 server(见下面的案例 C)。还有很多是把参数从单一的type改成了anyOf这类组合形式。我们的规则把这也算作 type 变化,所以会高估破坏。
三个案例
这些是我们数据里的真实 server。名字、确切日期和确切的工具数我们都没写,因为还没问过它们的维护者。
分步增长的 server。 一个月里,有个 server 的工具数增加了大约 60%,分了十次。每两次之间,它还在改描述和 schema。我们为它存了 40 多份变化后的列表。一个每周刷新一次这个 server 工具列表的 agent,大多数时候都缺着它最新的那些工具。
几乎所有工具都没了。 一个有几百个工具的 server,有一轮检测没完成握手。等它再次应答时,之前的工具名几乎全没了。两份列表都不带 nextCursor,所以不是分页造成的。拿着旧列表的 agent,会一直去调用已经不存在的工具。
number 变成 integer。 一次更新里,一个大型 server 把很多数值参数从 number 改成了 integer,描述没变。按新 schema 校验参数的客户端,前一天还接受 2.5,现在会拒绝。
协议版本
3,602 个 server 在最近一轮里完成了握手并声明了协议版本。另外 2,310 个没有:1,897 个在握手时就要求登录,412 个没完成握手,1 个被网络防护拦下。(另有一个需登录的 server 完成了握手,到 tools/list 才要求登录。)
| 版本 | server 数 | 占比 |
|---|---|---|
| 2025-11-25 | 1,803 | 50.1% |
| 2026-07-28 | 1,043 | 29.0% |
| 2025-06-18 | 595 | 16.5% |
| 2024-11-05 | 85 | 2.4% |
| 2025-03-26 | 75 | 2.1% |
| 其他 | 1 | <0.1% |
探测器先试 server/discover,提出 2026-07-28。server 不支持的话,就退回 initialize,提出 2025-11-25。
| 路径 | 应答 | 用我们提出的版本 | 更早的版本 | 更新的版本 | 无法识别 |
|---|---|---|---|---|---|
server/discover,提出 2026-07-28 |
1,059 | 1,039 | 20 | 0 | 0 |
initialize,提出 2025-11-25 |
2,543 | 1,797 | 741 | 4 | 1 |
| 合计 | 3,602 | 2,836 | 761 | 4 | 1 |
761 个 server(21.1%)回答的版本比我们提出的更早,最常见的是 2025-06-18(592 个)。用一个更早的、自己支持的版本回答,正是协议规定的协商方式,所以这不是毛病。它说明的是:公开可见的 server 里,仍有相当一部分讲的是 2024 年和 2025 年上半年的版本。
登录
最近一轮里,有 2,182 个 endpoint 对我们的某个请求回了 HTTP 401,分成两类。
- 1,916 个(87.8%)在握手或
tools/list时要求登录。- 其中 1,898 个拿到了需登录覆盖的签名证明;
- 17 个签不了,因为没拿到能做指纹的工具列表;
- 1 个被网络防护拦下。
- 266 个(12.2%)不带凭据就列出了工具。 它们只对我们调用一个不存在的工具名回了 401,签的是完整覆盖。
2,150 个带 WWW-Authenticate 质询的 401 里,2,011 个(93.5%)按 RFC 9728 的写法指向了一份 OAuth 受保护资源元数据文档。每份文档我们取了一次:
- 1,997 份和质询一致;
- 10 份声明的 scope 和质询矛盾;
- 4 份返回 HTTP 错误。
139 个质询没有给出元数据地址,另有 32 个 401 根本没带质询。
需登录的签名证明只覆盖不带凭据也能观察到的四项检查:可达性、重定向策略、传输方式和鉴权元数据。其余每一项都记为 UNVERIFIED 并写明原因。签名内容里记着覆盖范围,所以部分覆盖的证明不会被误当成完整的。需登录签名是 10 月 20 日开始的,在那之前,这样的检测都不签名。
方法
-
探测。 未认领的 server 每 12 小时从 Cloudflare Workers 探测一次。探测器从不发送凭据。它发送握手、
tools/list(只读第一页),以及一次对一个不存在的工具名的调用;第一页带nextCursor时,这次调用跳过。 -
检查状态。 每轮检测每项检查记一个状态:VERIFIED、FAILED、OBSERVED_RISK,或者带原因的 UNVERIFIED。
-
签名。 符合我们签名条件的检测会被规范化,用 Ed25519 签名,装进 DSSE 信封。签名把记录和我们的密钥绑定在一起,之后任何改动都能被发现。它不是对 server 质量的评价。未签名的检测就标为未签名。
-
公布的密钥。 密钥列表在
https://mcpcheckup.com/.well-known/mcpcheckup-keys.json。当前的密钥 ID 是70222b3a2c05e79a,自 2026 年 8 月 22 日起生效。 -
验证签名。 mcpcheckup/checks 里有规范化器、证明的 schema 和一个离线验证器。需要 Node.js 22.18+ 或 24+,不用安装:
curl -fsS https://mcpcheckup.com/.well-known/mcpcheckup-keys.json -o keys.json node packages/verifier/verify-attestation.mjs --envelope <file> --keys keys.json验证器不发任何网络请求。它检查每个签名的密钥 ID 在密钥列表里、没被吊销,并且签名内容里的
observed_at落在这把密钥的有效期内。keys/里有一份密钥列表的副本,可以完全离线验证。
局限
- 有两项检查还没开始运行。 5,912 个最近一轮里,TLS 证书和延迟两项都是 UNVERIFIED。
- 需登录的签名证明只覆盖四项检查。 登录之后的一切,都不在我们观察的范围内。
- 没记录传输方式。 我们没记 server 是通过 Streamable HTTP 还是旧式 SSE 应答的。
- 在线情况按天统计,而且窗口期间规则收紧过,见上文。
- 工具列表只读第一页。 分页的 server 不计入漂移数据。
- 有些描述变化是动态文本。「可能造成破坏」是只看顶层参数的近似规则:它不看嵌套 schema,还把改成
anyOf的情况算作 type 变化。 - 一个观察点,不带凭据。 登录后的用户,或者在其他地区的客户端,看到的情况可能不同。
- 7 天和 30 天的统计范围不同。 10 月列表增长很快,所以 7 天的范围(3,029 个)和 30 天的范围(815 个)是两组不同的 server,不要当成趋势来读。