跳到主要内容
MCP 的依赖没上锁

MCP 的依赖没上锁

一键三连
一键三连

· 阅读约 2 分钟

你每天让 agent 读多少次 tool description?每个会话还没开口,它就把能调的工具描述扫一遍,按描述决定调谁不调谁。而你——可能和我一样——从来没校验过那句描述还是不是你上次看过的。

MCP server 本质上就是没上锁的依赖。npm 有 lockfile,Cargo 有 lock,MCP 里什么都没有。没有版本约束,没有完整性校验,agent 信任的是一份随时会变的文本。它坏起来还特别安静:

改描述,不动 schema。工具列表照样显示,agent 的取舍却悄悄拐了弯。

加一个必填参数,你的 prompt 没跟上,agent 怎么填?看命。

readOnlyHint 从 true 翻 false——你以为的只读,现在能写了。

删掉某个工具,列表短了一截,你压根发现不了。之前一直好好的,突然就乱了——你别说你没见过。

几周前 dev.to 上有人把这层纸捅破了,管这叫 unpinned dependency。Invariant Labs 的 mcp-scan 从去年四月就开始用 tool hashing 盯描述变化。但盯归盯,光检测不行,得在 CI 里加一扇门。Tsvetan Gerginov 把这扇门做出来了,叫 mcpward。

机制一句话:把 server 的契约 snapshot 成 lockfile,跑 CI 时对比,漂移就 fail。

npx mcpward init
npx mcpward run

baseline 里记的是每个工具的 name、描述 hash、输入输出 schema、annotations。变更分 breaking 和 non-breaking 两类。breaking 那边列了一堆常规项——工具删了、描述变了、必填多了、类型收窄、枚举收紧——直到我看见最后这条:

readOnlyHint 从 true 翻 false,算 breaking,直接 fail。

⚡这一下就值回票价。工具作者自己可能都没意识到,把注解翻个面,对依赖它的 agent 来说就是一次行为变更。评论区还有人觉得 readOnlyHint 翻转该按安全事件处理,作者说在考虑给注解翻转单开一个 severity 档位。我看行。

功能不止这个:MIT,本地跑,没账号没遥测,black-box 对着任意 MCP server 扫,stdio 或 Streamable HTTP 都行。但功能多不多不是重点,重点是两条命令就能把“契约变了”变成一次明晃晃的 CI 失败。

不过有一句话我是翻评论区才注意到的,作者自己写的:unchanged contract 不代表 unchanged dependency。锁文件锁的是契约,不是信用。mcpward 防的是漂移,防不了蓄意投毒——真遇到恶意 server,它会先骗过你,再骗过锁。但我不觉得这是缺陷,这是它把边界说得清清楚楚。这种工具反而比那种宣称全能的更可信。

装到 CI 里大概十分钟。这周用下来,每次报 drift,省下来的都是半天起步的“之前好好的怎么就跑偏了”的排查时间。这笔账怎么算都回本。

你们有更快的防漂移办法?教教我。

更多「MCP」的实战

评论

还没有评论,写下第一条讨论。