跳到主要内容

MCP 可组合性陷阱:当「再加一个服务器」变成依赖地狱

· 阅读需 11 分钟
Tian Pan
Software Engineer

MCP 生态已拥有 10,000+ 服务器和 9700 万次 SDK 下载量。但同时也在六十天内出现了 30 个 CVE、502 个未锁定版本的服务器配置,以及一个在十五个版本中悄悄将每封外发邮件密送给攻击者的供应链攻击。可组合性的承诺——「只需再接入一个 MCP 服务器」——是真实的。但它带来的依赖蔓延也是真实的,大多数团队在深陷集成债务之后才发现其代价。

如果你在 npm 上构建过生产系统,你一定看过这部电影。MCP 生态正在加速重演同一剧情,只不过这次的「包」拥有对你机器的 shell 访问权限和生产系统的凭证。

npm 的类比并非隐喻

当人们将 MCP 生态的增长与早期 npm 相比时,通常是在夸奖——快速采用、充满活力的社区、可组合的构建块。但这个类比也延伸到了失败模式,而且失败模式更加严重。

对七个注册中心的 42,000+ MCP 工具进行扫描后,发现了与 npm 最严重供应链事件相似的模式。数据描绘出一幅具体的画面:

  • 502 个配置使用不带版本锁定的 npx,每次智能体启动时都拉取最新版本
  • 1,050 个配置指向没有证书固定或身份验证的远程 URL
  • 448 个配置启用了自动安装标志,跳过用户确认直接执行代码
  • 467 个工具引用了可变的 GitHub raw URL,分支更新时内容随之改变
  • 1,679 个工具包含嵌入式 pip 命令;742 个包含系统包管理器

与 npm 的关键区别在于:npm 包在沙箱中运行。MCP 服务器以完整的机器访问权限执行——你的文件系统、你的 shell、你的凭证。2018 年 event-stream 攻击中,一个被入侵的维护者影响了数百万次下载。但爆炸半径被浏览器沙箱所限制。MCP 没有等效的隔离机制。

2026 年初的 postmark-mcp 攻击完美地证明了这一点。攻击者在十五个看似正常的版本中建立信任,然后加入代码将每封外发邮件密送到外部地址。由于 MCP 服务器拥有合法的邮件发送权限,恶意行为在工具调用层面与正常操作无法区分。

信任模型默认就是有缺陷的

大多数 MCP 客户端实现的是首次使用即信任(TOFU)。你在初始设置时批准一个服务器,后续更新不再验证。这创造了一个窗口期,已批准的服务器可以在此期间被悄悄入侵——而这正是攻击者瞄准的窗口。

当你考虑大多数团队实际管理 MCP 配置的方式时,问题会进一步恶化。服务器引用存在于 JSON 配置文件中,通常被提交到仓库或在团队间共享。一个典型的智能体配置可能引用八到十二个 MCP 服务器,每个都有自己的版本(或没有版本)、凭证和信任假设。

以下是会出问题的地方:

  • 静默更新:没有版本锁定,你的智能体能力在每次重启时都会改变。昨天正常的服务器今天可能暴露不同的工具,或者同一工具的行为可能不同。
  • 凭证蔓延:88% 的 MCP 服务器需要凭证,但 53% 依赖以环境变量传递的长期静态密钥。当你运行十个服务器时,就有十组凭证,没有集中吊销机制。
  • 继承权限:MCP 规范不包含授权机制。每个服务器继承它被授予的所有权限,每个请求未经验证就直接通过,除非你添加外部控制。

2026 年 1 月至 2 月期间,研究人员针对 MCP 基础设施提交了超过 30 个 CVE。漏洞范围从简单的路径遍历到 CVSS 9.6 的远程代码执行缺陷(该包被下载近 50 万次)。根本原因是一致的:缺少输入验证、没有身份验证,以及对工具描述的盲目信任。

规模化工具冲突:发现问题

可组合性的承诺假设添加服务器是累加的——更多服务器意味着更多能力。实际上,组合 MCP 服务器会产生在导致故障之前不可见的冲突。

最直接的问题是工具命名。当两个服务器暴露同名工具时,智能体必须选择一个,而解析策略因客户端而异。有些选择最后注册的服务器。有些报错。有些悄悄地用一个工具遮蔽另一个。当你没有预料到冲突时,这些结果都不正确。

命名空间——像 calendar.list_eventsslack.search_messages 这样的前缀——解决了语法冲突。但语义冲突更难处理。两个不同的 MCP 服务器可能都提供 send_email 工具,但参数模式、认证上下文和副作用各不相同。智能体看到两个做大致相同事情的工具,必须仅基于描述来选择。

随着工具数量增长,情况会更糟。工具选择准确性的研究表明,随着工具库规模扩大,智能体性能会下降——四个工具时运行良好的东西,到五十个时就变得不可靠。你添加的每个 MCP 服务器不仅仅是增加能力;它在扩大智能体每次操作时必须导航的决策空间。

MCP 提供的能力协商——客户端和服务器在初始化握手中声明支持的特性——处理的是协议级兼容性。它不处理来自不同服务器的、操作同一领域的工具之间的语义兼容性。这个问题完全留给了智能体的推理能力,也就是说留给了运气。

加载中…
References:Let's stay in touch and Follow me for more thoughts and updates