我们为何构建托管式 MCP 服务器以阻止 AI 代理的恶意软件包

AI Agents 安装包,但不审查包

Claude Code、Cursor、Codex 是新一代 AI 编程代理。它们可以比大多数人在阅读 README.md 的时间内更快地搭建项目、编写功能并连接依赖项。但它们也会毫不犹豫地运行 npm install

这就是有趣的地方。这些代理完全没有能力区分合法包和恶意包。与代理可以审查的第一方代码不同,它们对通过开源包依赖继承的第三方代码没有任何可见性。

它们会安装任何基于名称、提示词和训练数据看起来正确的东西。而攻击面是真实存在的。我们花了一年的时间来分析它:

  • Shai-Hulud 2.0:一种自我复制的蠕虫,感染了 zapier-sdk@asyncapiposthog 包——影响了超过 500 个 npm 包和 25,000+ 个仓库。恶意软件通过 preinstall 脚本传播并窃取云凭证。
  • eslint-config-prettier:每周 3000 万次下载。通过对维护者 npm 账户的网络钓鱼攻击被入侵。在被人发现之前发布了六个恶意版本。
  • nx build system:每周 460 万次下载。通过 postinstall 钩子窃取凭证——恶意软件在开发者运行 npm install 时立即执行。
  • 21 个带有加密货币钱包 drainer 的 npm 包:累计每周下载量超过 10 亿次的包,被武器化用于窃取加密货币。

然后是 slopsquatting(错误拼写劫持)。AI 模型会产生不存在的包名称幻觉,为攻击者创造了注册这些名称并植入恶意软件的机会。Spracklen 等人 测量到商业模型的幻觉率为 5.2%,其中 58% 可重复。这意味着这是一个可靠、可自动化的攻击向量。

传统的 SCA 工具在 CI/CD 管道中运行。当它们标记出一个恶意包时,npm install 已经执行了开发者机器上的 postinstall 钩子。安装本身就是攻击。不存在任何"安装后扫描"能提供帮助。

我们的第一次尝试:通过 MCP 暴露现有 API

我们已经有了 vethttps://github.com/safedep/vet),这是一个开源的 SCA 工具,用于扫描依赖项中的漏洞、恶意软件和供应链风险。当模型上下文协议(MCP)成为代理与工具集成的标准时,路径似乎很明确:将 vet 的能力(数据)暴露为 MCP 工具,让代理在安装任何东西之前调用它们。

我们构建了一个本地 vet MCP 服务器,发布并写了相关文章。设置很简单。将 vet 作为 Docker 容器运行,与 MCP 兼容的编码代理集成。

我们以为它可以直接工作。

MCP 工具不仅仅是另一个 API

当我们在真实项目上让 vet MCP 服务器与 Claude Code 进行内部测试时,三个问题很快就变得清晰了。

上下文溢出

原始威胁情报数据淹没了代理的上下文窗口。单次包查询返回详细的漏洞报告、依赖树、许可证元数据、分析时间戳、vet 知道的关于一个包的所有信息,以结构化输出形式全部倾倒。

例如,当 vet MCP 在 Claude Code 中加载时,它为我们的开源威胁情报(insights)服务的每个逻辑 API 注册一个工具:

vet MCP Multiple Tools

不仅消耗了更大的上下文窗口来容纳工具描述和其他元数据,当 API 响应较大时还经常失败。

vet MCP Context Overflow

Claude Code 反复触发上下文压缩。这不是一个后端 API 的问题,因为它们是为机器使用而设计的,不会受到 AI 代理上下文窗口限制的影响。

代理无法在其内存中同时保存用户的实际任务和所有这些威胁数据。在检查了几个包之后,对话质量下降,代理失去了对正在构建内容的跟踪,开始产生幻觉。

工具可靠性

代理在应该使用工具时并没有可靠地使用它们。有时 Claude Code 会完全跳过包检查,直接进入 npm install。其他时候它会调用错误的工具或误解输出。

工具描述和输出格式与底层数据同样重要。MCP 工具不是开发者阅读并据此行动的 API 端点。它被语言模型消费,语言模型需要在一轮交互中理解结果意味着什么以及该做什么。

例如,一个简单的提示:Check the security of npm package nx 会导致工具以非确定性顺序调用:

  • 直接调用漏洞检查工具但不提供版本号而失败
  • 调用漏洞检查工具但完全错过调用恶意包检查工具
  • 调用漏洞检查工具但使用错误的版本号

看起来这个问题需要一个更简单的解决方案供代理使用。一个单一的工具来回答问题——一个开源包是否可以安全使用?

"恰到好处"的上下文问题

MCP 工具的输出与用户的实际任务竞争空间(上下文)。每一条威胁情报的 token 都是代理无法用于代码生成、调试或架构推理的 token。

输出需要:

  • 足够简洁,不浪费上下文预算
  • 足够结构化,代理可以解析并据此行动
  • 足够果断,代理知道该怎么做。阻止、允许或询问开发者

vet MCP 服务器暴露的 API 是为机器渲染人类可读的报告而设计的。不是为 LLM 做决策而设计的。

这是核心洞察:​MCP 的上下文工程是一门学科。​工具输出必须为 LLM 消费而设计,而不是为人类消费而设计。做错这一点会导致结果质量下降,给开发者带来摩擦。

我们构建了什么

我们从头开始重建了 MCP 服务器,作为托管服务运行在 mcp.safedep.io。架构在三个方面发生了根本性变化。

云原生威胁情报。​托管服务器由同一个实时威胁情报数据库支持,该数据库检测到了 Shai-Hulud 2.0eslint-config-prettier 被入侵事件nx build system 攻击 以及 21 个 npm 包上的加密钱包 drainer。没有本地 Docker 容器,没有过时的数据库。情报通过我们的恶意包扫描基础设施持续更新。

单一工具提供指令而非数据。​根本性转变之一是摆脱通过 MCP 工具暴露后端 API 的模式,转而提供引导代理的工具。例如,使用 SafeDep 托管 MCP,代理上下文中只加载一个工具。

SafeDep MCP Single Tool

经过上下文工程设计的输出。​每个工具响应都是为 LLM 消费而塑造的。服务器不是转储完整的漏洞或恶意包报告,而是返回简明的裁决,并附带足够支持证据让代理做出决定。我们根据代理的实际行为迭代调整输出格式、token 预算和工具描述。

SafeDep MCP Tool Output

持续元数据调优。​工具描述、参数模式和输出格式在服务器端更新。当我们发现代理在某些上下文中误解字段或跳过工具时,我们一次性修复,每个用户立即获得改进,无需手动更新。

看它如何工作:在几分钟内阻止恶意包

步骤 1 — 获取凭证

app.safedep.io 注册(免费层,无需信用卡)。导航到 Settings → API Keys。复制你的 API 密钥和租户 ID。

步骤 2 — 添加 MCP 服务器

将凭证设置在环境变量中以避免通过 shell 历史记录泄露:

bash
export SAFEDEP_TENANT_ID=<your-safedep-tenant-id> export SAFEDEP_API_KEY=<your-safedep-api-key>
bash
claude mcp add safedep-threats \ --transport http \ --header "Authorization: $SAFEDEP_API_KEY" \ --header "X-Tenant-ID: $SAFEDEP_TENANT_ID" \ https://mcp.safedep.io/model-context-protocol/threats/v1/mcp

注意:如果你有正在运行的实例,请重启 Claude Code。

步骤 3 — 测试它

提示 Claude Code 安装一个已知的恶意测试包:

plaintext
Install the npm package safedep-test-pkg
SafeDep MCP Block Demo
plaintext
Install the npm package express
SafeDep MCP Allow Demo

干净的包可以正常进行,不会产生摩擦。

Cursor 和其他代理

对于 Cursor、Windsurf 和其他 MCP 兼容的代理,请访问我们的 MCP 设置页面 获取可直接使用的配置。JSON 配置遵循相同的模式:

json
{ "mcpServers": { "safedep-threats": { "type": "http", "url": "https://mcp.safedep.io/model-context-protocol/threats/v1/mcp", "headers": { "Authorization": "YOUR_API_KEY", "X-Tenant-ID": "YOUR_TENANT_ID" } } } }

局限性

软件供应链很复杂。开源依赖管理、包管理器和整个依赖图尤其如此。开源包不是一次性用品,它们有自己的依赖项。顶级依赖项由开发人员控制,现在也由 AI 代理控制。传递依赖项也携带风险。代理操作的性质限制了可见性和安全检查只能针对直接依赖项,这是 MCP 服务器基于护栏方法的做法。我们相信这为防范恶意开源包提供了合理的安全保障。但是,如果你偏执并需要额外的安全保障,我们建议尝试我们的开源项目 PMG。PMG 利用微代理和沙箱进行深度包分析,并采用操作系统强制的功能限制来防范已知和未知的攻击。

后续计划

我们将继续根据真实的代理交互来优化工具输出。上下文工程是一门持续的学科,不是一次性优化。生态系统扩展正在进行中,覆盖范围超越 npm 和 PyPI。

开始使用并保持安全:

SafeDep 博客的最新内容

关注以获取开源安全与工程的最新更新和见解