为什么 MCP Checkup 不运行你的代码(以及这对 stdio server 意味着什么)
本文译自 2026-09-14 的英文原文。
目前 MCP Checkup 只收录远程 MCP server:有 HTTP URL、任何客户端都能连上的 endpoint。stdio server 的维护者会问我们什么时候轮到他们,这很合理。要回答这个问题,得先简单绕一下,说说 stdio server 到底是什么。
地址与软件包
远程 server 不管有没有人在看,都在那里。它有 URL,会应答请求;观测它,就是发出客户端本来就会发的那些请求。这一切都不需要信任 server 的代码:我们站在外面,读它返回的东西。
stdio server 没有 URL。它是 npm 或 PyPI 上的一个软件包。只有当有人下载它、安装它(而 npm install 本身就会通过生命周期脚本执行任意代码),再把它作为自己客户端的子进程启动时,它才以进程的形式存在。「探测」一个 stdio server 这回事并不存在。只有一个问题:这份代码在谁的机器上运行?
这个问题有三个诚实的答案,它们的可信程度并不相同。
我们今天守住的线
我们不在自己的基础设施上执行维护者的代码。不在容器里,不在沙箱里,也不「只为拿到 tools/list」。原因不是洁癖。一个会运行不受信任软件包的检查器,就是一台按计划安装互联网塞给它的任何东西、同时握有为结果签名的凭据的机器。把这件事做对是一个严肃的安全项目,需要单独审查;在那份审查完成并公开之前,正确的代码执行量是零。
这也是为什么在远程 server 上,探测器从不调用你的任何工具。tools/list 描述的是一个工具会做什么;调用列出来的工具,就是真的去做。我们止步于描述。探测器确实会发出的那一次 tools/call,调用的是一个不存在的工具 __mcpcheckup_probe_nonexistent_tool__,只为看看 server 怎样拒绝它。
我们正在设计的三层
下面这几层都还没有上线。这是设计稿,公开出来,是为了让 stdio server 的维护者看到方向,并在方向不对时告诉我们。
A 层:静态分析,不执行。 取回锁定版本的 tarball,不安装,不运行。读 package.json 里声明的 SDK 版本、入口和引擎约束;解析源码里静态注册的工具定义;记下是否存在生命周期脚本;用已知的漏洞数据核对依赖。这一层产出的一切都标为「静态分析」。凡是它确定不了的,比如运行时才注册的工具、真实的 tools/list,都标为未检查,并附上这个原因。
B 层:由你的 CI 跑检查。 你自己仓库里的一个 GitHub Action,在你的 runner 上取回、安装、启动软件包,完成握手和 tools/list,并计算指纹。回到我们这里的只有指纹和元数据,没有源码,也没有构建产物。这些结果标为「自我声明」,因为它们就是这样:你的基础设施说它看到了什么。
C 层:在隔离环境中独立执行。 等托管执行的安全审查完成之后,并且只在维护者授权的前提下,我们在隔离环境里跑同样的检查。这些结果会标为「独立观测」,也只有这一层能诚实地与远程探测分量相当。
三层的可信程度不同,所以设计要求报告页和 API 都写明每条断言出自哪一层,字段里写,屏幕上也写。「你的 CI 说它通过了」和「一个独立的第三方在隔离环境里复现了它,并签了名」是两种不同的产品,把它们压成同一个徽章,就是用省略来撒谎。
在那之前能做什么
如果你的 server 有远程模式,那个 endpoint 今天就可以被收录和认领,本站的一切都适用于它。如果它只有 stdio,眼下还没什么可做的;我们宁可直说,也不愿挂出一个只显示包名和十五行「未检查」的页面。
A 层上线时,我们会在这里说明,它的局限会写在它产出的每一个页面上。