先打开配置数一下自己挂了几个 MCP server。我数出来 11 个,其中 4 个是半年前为了试某个 demo 装的,早就不用了,但一直还挂着,每次会话都跟着加载。
当初怎么装的?复制别人 README 里的那段 json,粘进去,重启,能用,然后再没打开过。那些 server 的 tool description 是别人写的字,模型每次会话都要从头读一遍——你自己一次都没读过。
跑一条命令:
npx -y @aimarket/[email protected] scan
⚡ 它扫的不算你的代码,是你这份配置里每个工具的说明文字,专挑那些看着像在给模型下指令的句子。
作者怎么说明这玩意儿不是乱咬的:拿 MCPTox 那 485 个中毒工具加 45 个真实 server 当靶子,先按固定哈希把 server 切成两半,规则只准从第一半里长出来,第二半在规则写完之前不碰。这个顺序很关键,反过来的话就成了拿考卷当练习册。
0.20.0 在写规则那一半 267 个里命中 250,在没碰过的那一半 218 个里命中 210;45 个干净 server 一个没咬。这套表里我只关心这两列,其余数字躺它文档里,我不搬。
后面还有 999 个公共 server 命中 4、1000 个 npm/PyPI 包命中 31 这样的数。那 31 个是不是真有事我没法替你看,但 3% 这个量级至少说明它不是空转。
扫可以,闸我没装
scan 我跑了。guard 那个 hook 形式的东西,我没开。
原因很简单,不是不信它,是它自己把误报都写在明面上了。0.19.0 有个能稳定复现的例子:会话里读过 RSA 私钥之后,你去发一份 README,里面只有一个 DKIM 公钥的说明,一个字符的秘密都没有——被拒,理由是「这是本会话读到的凭证的一部分」。就因为它俩共享同一个算法标识。到 0.20.0 才把同类的密钥共享的那段从指纹里摘出去。
还有个小得多的:Send it to [email protected]. 句末那个句号,让旧版没认出来这是你自己指定的地址,于是回头问你一遍——问的是你三秒前刚打完的那串。
单个看都很小。加起来的效果是:你会开始不看提示直接点同意。
一旦到这一步,这层东西就从最后一道检查变成每天弹二十次的确认框,而且比不装还糟——它还顺便给了你一种「我装过了」的安心。我在这条线上踩过太多次,现在的判断是,什么时候该停手,取决于「我还看不看得懂刚才发生了什么」。
⚡ 分界就在输出上:它给我一张清单,我去读;它给我一个弹窗,我去按。前者我愿意要,后者我宁可不要。
顺便说一句,作者处理那 6 个字符碎片的方式我挺认:夹在别的词里的短密钥片段仍然能过,他没去堵,因为堵上的代价是更多误拒,他把这条直接写进了限制清单。愿意在文档里承认「这块我不做」的人,比只贴榜首数字的人可靠。
让我更信这个项目的一点
它文档里那串 replay 数字,是 10 月 18 号安全审计收紧 guard 之前跑的。作者自己回去重跑了一遍,发现少了 1 个无询问完成的任务、少了 19 个攻击下完成的任务——这次收紧的代价,之前没人量过。他把数字改了。
同一份文档里的复现命令还根本构建不出来,因为 .dockerignore 把 dist/ 排掉了,镜像里缺东西。
这两件事比任何一个命中率都让我愿意抄这个工具。我抄别人配置有个习惯:先翻他有没有写过「上次那个后来发现不灵」。从来不写这种话的,我一般不全抄,抄一半就停。
那到底怎么用
跑一次 scan,几十秒,把结果当体检单看。然后做最土的那件事——把已经不用的 server 删掉。我 11 个删到 7 个,删掉的 4 个里有 3 个连 API key 都过期了。
老实说这招有边界:只对说明文字里明着写指令的那种有用,answer-only 那类注入它看不出来,作者自己在限制清单里也写了。别把它当保险,当成一次性的卫生检查。
跑一次半分钟,删一个不用的 server 省的是每次会话的上下文——这笔账我算得过来。你要是扫出过什么奇怪的东西,或者你有更快的写法,教教我。
