我在 Docker 里启动了 10 个 MCP 服务器。同一个版本跑两次,有个工具的描述却变了

Dev.to AI 2026-10-28T09:54:35.299830

我们运行了 AgentShortlist,这是一个 MCP 服务器目录,每一条记录都有来源。以下是我们的自有数据。服务器工具描述的哈希值,在没人改动代码的情况下,两次运行之间也可能发生变化。我们在 Desktop Commander 0.3.1 上就遇到了这种情况。两次运行之间,只有 start_process 的描述不同,而那段文本里唯一的差异是一个 Docker 容器 ID:一次运行中是 fd1cb95d1f61,另一次是 6f6d4f1f57de。它位于一段长 4180 个字符的描述的第 1348 个字符处。schema 和其他 24 条描述完全一致。我们起初以为工具本身出了什么变化,其实并没有。该服务器会把容器主机名写进描述里,所以文本取决于它运行在哪里。这是环境造成的效果,不是漏洞,也不是风险的信号。我们当天就更正了自己的记录。对那些通过哈希 tools/list 来监控 MCP 服务器变化的人来说,实际教训是:比较在同一环境中取得的哈希,或者在哈希之前去掉主机名和路径。否则,一个无害的容器 ID 看起来就像工具被改动了。本文剩下的部分,是那几次运行还记录了什么。

我们运行了什么

2026 年 10 月 25 日,我们在一台装有 WSL2 的 Windows 机器上,从我们已验证的卡片中把 10 个服务器安装到 Docker 里,不使用任何凭据,只使用合成数据。其中七个运行在 node:22-slim 中。三个(excel、fetch、git)运行在一个带 uv 和 Python 3.12 的镜像里;git 那个还需要安装 git,第一次没装就没有启动。对每一个,我们都用探测脚本发送 initialize 和 tools/list,并保存工具名称以及规范列表(按名称和键排序)的 sha256,描述、schema 以及两者合并各有一个单独的哈希。记录存放在每张卡片的“Tested by us”下面。全部 10 个都通过了。这里的“通过”意味着三件事:包安装并启动成功,用有效的协议版本回应了握手,并且返回了工具列表。它并不意味着这些工具能正常工作,不意味着它们会像描述所说的那样行事,也不意味着项目文档里写的任何限制都成立。在第一次运行中,我们没有调用任何工具。

同一天稍晚又跑了一轮,给其中四个服务器(memory、everything、git 和 fetch)各加了一次无害调用,用的是合成数据,结果记在各自的卡片上。

服务器 版本 工具数
excel-mcp-server 2.2.2 46
chrome-devtools-mcp 1.12.0 32
@playwright/mcp 0.0.83 25
Desktop Commander 0.3.1 25
codebase-memory-mcp 0.12.1 17
server-everything 2.0.0 16
mcp-server-git 2026.10.19 12
server-memory 2.0.0 9
Context7 4.4.4 2
mcp-server-fetch 2026.10.19 1

Playwright 的数量指的是它的默认工具集。它的 README 里还提到更多工具,藏在可选的 --caps 分组后面,我们没有启用。

同一个哈希出现两次,还是只有一次

有八个服务器(chrome-devtools、codebase-memory、Context7、excel、memory、everything、git 和 fetch)两轮运行给出了完全相同的哈希。Desktop Commander 跑了两轮,结果不同,原因如上。Playwright 的记录里看不到第二轮,所以再跑一次仍可能不同。只有一对结果相同,这只能算稳定性的弱证据,谈不上证明。

从名字能看出什么

仅凭工具名,我们按它们看起来做的事做了分组。规则是公开的,而且故意做得简单:名字里带 start_process 就算执行命令,带 write_file 就算写文件。这些分类只看名字,既不代表工具内部实际做什么,也不代表服务器会施加什么限制。一个叫 read_file 的工具完全可能拒绝读取大多数路径,这一点我们没测。

在此前提下,有几个名字在连接服务器之前值得先了解:

server-everything:它有一个名叫 get-env 的工具,从名称看是用来返回环境变量的。我们没有调用它。这个项目是供测试客户端使用的参考服务器,所以这并不能说明它在正常使用时会暴露什么。

mcp-server-fetch:它只有一个工具 fetch,从名称看是用来访问网络的。

这些分组存在空缺。对 codebase-memory 来说,17 个工具名里有 16 个不属于任何分组;对 Context7 来说,它的两个工具也都不属于任何分组。这不代表这些工具是无害的,只说明我们的命名规则对它们给不出任何结论。这些服务器的卡片会显示有多少工具落在所有分组之外。

一处统计出错

Desktop Commander 的卡片写着 24 个工具,这个数字是我们在撰写卡片时从源码里数出来的。但运行时,服务器为我们的测试客户端列出了 25 个工具。我们查看了该项目主分支上的 src/server.ts,其 package.json 标注的版本是 0.3.1。它定义了 25 个不同的工具名,与服务器返回的 25 个一致。其中 give_feedback_to_desktop_commander 这个工具在连接方客户端名为 desktop-commander-app 时会被排除,所以对那个客户端而言,列表只有 24 个。卡片上会写 25,并注明数量取决于客户端。

这些结果没有说明的问题

除了在四台服务器上各做过一次无害调用之外,我们没有测试任何工具是否真的能用、处理真实数据时表现如何,也没有测试运行它是否安全。在同一台机器、同一天跑通十次,只能说明这些包在那个环境下能安装成功,并且能响应一个基本请求。对任何一台服务器,连接之前请先看卡片上的其他信息(每行来源、advisories 安全公告、访问类型),如果发现哪里有问题,请使用卡片上的报告链接。

带逐服务器卡片的完整文章:https://agentshortlist.dev/blog/10-mcp-servers-in-docker-what-their-tool-lists-tell-you?utm_source=devto

我们还发布了一份关于 MCP 安全公告的简要说明,叫 MCP Risk Radar:https://agentshortlist.dev/radar?utm_source=devto

我运营着 AgentShortlist,这是一个 MCP 服务器目录,每条记录都标注了来源。下面这些数据来自我们自己的实测。

同一个版本,代码没人碰过,服务器工具描述算出的哈希值,却可能在两次运行之间变掉。Desktop Commander 0.3.1 就出现过这种情况。两次运行中,只有 start_process 这个工具的描述不一样,而那段文字里唯一的差异,是一个 Docker 容器 ID:一次是 fd1cb95d1f61,另一次是 6f6d4f1f57de。它落在一段 4180 个字符的描述的第 1348 个字符处。

而 schema 这一部分……

查看原文