内容
# <img src="https://raw.githubusercontent.com/appcreationsca/bumpguard-mcp/main/assets/logo.png" alt="BumpGuard logo" height="44" align="top">BumpGuard
<!-- mcp-name: io.github.appcreationsca/bumpguard -->
**保护你的依赖升级。** BumpGuard 是一个 [模型上下文协议](https://modelcontextprotocol.io)(MCP)服务器,它能告诉你的 AI 编码代理 **哪些代码行在升级依赖时会被破坏** —— 并验证 AI 编写的代码是否符合 **实际安装的 API**,以防止调用不存在的函数。
它通过 **静态分析** 实现这一点。BumpGuard 从不导入或执行第三方代码;它直接从源码读取软件包的实际公共 API。
> 文档告诉你的代理应该存在什么。BumpGuard 告诉它在这里实际存在什么。
<p align="center">
<img src="https://raw.githubusercontent.com/appcreationsca/bumpguard-mcp/main/assets/demo.gif"
alt="BumpGuard check_upgrade demo: out of 2,015 breaking changes in pydantic 2.0, it flags the one (BaseSettings) that hits your code, with the fix"
width="820">
</p>
---
## 为什么存在
开发者在使用 AI 编码工具时报告的 #1 挫折是代码 **“几乎正确,但不完全正确”**。其中很大一部分原因是 **API 漂移和幻觉**:
- 模型编写了 `pydantic.BaseSettings` 或 `openai.ChatCompletion.create(...)` —— 完美有效,但在两版本前,**在你安装的版本中已消失**。
- 你将 `pandas` 从 1.5 升级到 2.2,并通过一次堆栈跟踪发现破坏。
- 更新日志列出了 *1,800 个破坏性更改*;你只关心 **实际影响你代码的三个**。
BumpGuard 通过提供来自你环境的真实信息来弥补这一差距,而不是模型的记忆。
---
## 功能
一个真实的例子 —— 在使用 `BaseSettings` 的代码中将 `pydantic` 从 1 升级到 2:
```jsonc
// check_upgrade(package="pydantic", to_version="2.0.3", from_version="1.10.13", code="...")
{
"safe_to_upgrade": false,
"summary": { "breaking": 1, "total_api_changes": 4919, "breaking_api_changes": 2015 },
"findings": [
{
"symbol": "pydantic.BaseSettings",
"line": 2,
"severity": "breaking",
"message": "你使用了 'pydantic.BaseSettings',它在目标版本中不再存在...",
"suggestion": "考虑使用 'pydantic.v1.env_settings.BaseSettings'"
}
]
}
```
在 **2,015 个破坏性 API 更改** 中,BumpGuard 显示了 **影响此代码的更改** —— 带有行号和修复提示。
---
## 工具
| 工具 | 回答的问题 |
| --- | --- |
| **`check_upgrade`** ⭐ | *"如果我将 `package` 升级到 `to_version`,代码中哪些部分会破坏?"* 将已安装(或 `from_version`)的 API 与目标 API 进行比较,并报告代码实际受到的影响,附带严重性和修复提示。 |
| **`diff_versions`** | *"两个版本的库之间有什么变化?"*原始的破坏性更改列表,无需代码扫描 —— 适用于计划迁移。 |
| **`verify_snippet`** | *"代码中的导入和 API 调用是否真的存在?"* 捕获虚构/拼写错误的软件包名称(域名抢注)和属性,这些属性不在已安装的软件包上。 |
| **`check_import`** | *"是否安装了此软件包?如果不是,什么是最接近的实际名称?"* |
| **`list_symbols`** | *"此软件包的实际公共 API 是什么?"*发现函数/类/方法 + 签名,而不是猜测 —— 适用于已安装的版本或任何已获取的版本。 |
| **`list_languages`** | 支持哪些生态系统提供商。 |
每个答案都基于证据(已安装的版本,源代码位置)。由于分析是静态的,**“无发现”意味着“未证明不安全”,而不是保证** —— BumpGuard 在其输出中对此明确表示。
---
## 安装
```bash
pip install bumpguard-mcp
```
需要 Python 3.10+。服务器通过 stdio 使用 MCP。
> 将 BumpGuard 安装到 **与您正在处理的项目相同的环境中**,这样它就能看到您实际安装的软件包。
---
## 配置你的 MCP 客户端
**Claude Desktop / Claude Code** (`claude_desktop_config.json`):
```json
{
"mcpServers": {
"bumpguard": {
"command": "bumpguard-mcp"
}
}
}
```
**Cursor / Windsurf / VS Code (Copilot)** — 将你的 MCP 配置指向 `bumpguard-mcp` 命令(或 `python -m bumpguard.server`)。任何兼容 MCP 的客户端都可以使用。
然后询问你的代理类似的问题:
- *"在将 pandas 升级到 2.2 之前,检查我的数据管道是否会中断。"*
- *"验证此代码段是否实际使用了已安装的 OpenAI SDK。"*
- *"列出 `httpx.Client` 上的实际方法。"*
---
## 工作原理
```
┌──────────────── 语言中立的核心 ────────────────┐
MCP 工具 → │ 差异引擎 · 破坏性更改分类器 · 分析器 │
│ (匹配 API 更改与您的用法) │
└───────────────────────┬──────────────────────────────┘
│ 提供商接口
┌───────────────────────┴──────────────────────────────┐
│ Python 提供商 │ .NET (NuGet) │ Java (Maven) │
│ • AST 表面 │ • DLL 元数据 │ • jar 字节码 │
│ • 用法扫描器 │ • Roslyn 扫描 │ • 源代码扫描 │
│ • 轮子获取 │ • nupkg 获取 │ • jar 获取 │
└──────────────────────────────────────────────────────┘
```
1. **提取** 软件包的公共 API 表面,通过解析其源代码与 Python 的 `ast` —— 对于已安装的版本和目标版本(下载为轮子并解压,**从未安装或执行**)。
2. **差异** 两个表面成已删除/签名更改/添加的符号,并将每个符号分类为破坏性、可能破坏性或信息。
3. **扫描** 你的代码(同样通过 `ast`)以查找用法 —— 解析导入别名、重新导出、实例方法调用以及每个调用传递的关键字/位置参数。
4. **匹配** 用法与更改并报告精确的、逐行的判决。
**安全性:** BumpGuard 从不导入第三方代码,因此没有导入副作用、重包导致的挂起或任意代码执行。轮子下载被沙盒化到临时目录、时间有限且受到路径遍历/ zip 炸弹的保护。
---
## 多语言设计
BumpGuard 围绕 **可插拔的提供商接口** 构建。差异引擎、破坏性更改分类器、分析器、报告和 MCP 工具都是语言中立的;只有 **表面提取** 和 **用法扫描** 是特定于生态系统的。
- ✅ **Python (PyPI)** — 现已可用。
- ✅ **.NET (NuGet)** — 现已可用。通过反射仅加载读取程序集元数据;需要 **.NET SDK** (`dotnet`) 在 PATH 上。第一次使用时会生成一个小型助手。
- ✅ **Java (Maven)** — 现已可用。直接从编译的 `.jar` 字节码读取公共 API(常量池、访问标志、描述符)**纯 Python** —— **无需 JDK 或 Maven** 且不执行第三方代码。
- 🔜 **JS/TS (npm)** — 解析 `.d.ts` 声明。
添加生态系统意味着实现一个 `Provider` —— 请参见 [`docs/ADD_A_PROVIDER.md`](docs/ADD_A_PROVIDER.md)。
### .NET 详细信息(v1)
- 传递 `language: "dotnet"`。示例: *"在将 Azure.AI.OpenAI 升级到 2.1.0 之前,检查我的客户端代码是否会中断(from_version 1.0.0-beta.17)。"*
- 支持:`check_upgrade`、`diff_versions`、`list_symbols`、`check_import`。
- **优先传递 `from_version`** —— “已安装”的基线来自 NuGet 全局缓存,这不是您的项目的固定版本。
- 可靠信号:**类型/方法/属性删除和添加** (例如,`OpenAIClient` → `AzureOpenAIClient` 重命名被捕获为带有建议的破坏性删除)。仅对 **明确的单一重载** 成员运行参数级差异;跟踪重载成员时存在(文档中记录的 v1 限制)。
- 完全限定的引用被自信地报告;通过 `using` 解析的短名称被报告为 **较低置信度的“可能破坏”** 以避免命名空间冲突的假硬中断。
- `verify_snippet` **不支持 .NET(v1)** (准确的 C# 幻觉检测需要语义绑定)。
### Java 详细信息(v1)
- 传递 `language: "java"` 并通过 Maven **坐标** `group:artifact` 标识软件包(例如 `com.google.code.gson:gson`)。示例: *"在将 com.google.code.gson:gson 升级到 2.10.1 之前,检查我的代码是否会中断(from_version 2.8.9)。"*
- 支持:`check_upgrade`、`diff_versions`、`list_symbols`、`check_import`。
- 公共 API 表面直接从 `.jar` 字节码读取(jar 是 `.class` 文件的 zip;BumpGuard 使用 `struct` 解析类文件结构 —— 读取元数据,从不运行它)。目标 jar 从 **Maven Central** 获取(沙盒化、大小上限、时间限制)。 **无需 JDK/Maven**。
- **优先传递 `from_version`** —— “已安装”的基线从您的本地 `~/.m2` 缓存读取,这可能与您的项目的固定版本不匹配。
- 可靠信号:**类型/方法/字段/构造函数删除和添加**,以及 arity 更改。完全限定的引用会硬中断;通过 `import` 解析的短名称被报告为 **较低置信度的“可能破坏”** 以避免命名空间冲突的假硬中断。
- 文档中记录的 v1 限制:泛型在字节码描述符中 **被擦除** (因此泛型类型参数更改不可见);**仅返回值** 更改和 **varargs 删除** 被保守地跟踪;**重载** 成员按存在情况跟踪(不检测每个重载的删除);多发布 jar 使用最高版本叠加。源代码用法扫描器是一个强大的启发式方法,而不是完整的解析器 —— 它可以捕获名称自己的 **声明** 或 `import` 行作为引用,但这些解析为不合格名称,这些名称上限为 **“可能破坏”** 且永远不会产生假硬中断。 `verify_snippet` **不支持 Java(v1)** (准确的幻觉检测需要语义绑定)。
---
## 已知限制(v1,Python)
BumpGuard 对静态分析是诚实的。它可能会 **遗漏** (假阴性)或很少 **过度标记** (假阳性):
- 动态生成的 API(`__getattr__` 模块、插件注册表、`boto3` 样式客户端)。BumpGuard 检测 `__getattr__` 模块并 **抑制** 在它们下的自信的“缺少符号”发现。
- 在运行时创建的成员在源代码中不可见。
- 编译(C/Rust)扩展内部 - 仍然读取 Python 级别的表面。
- 深入的实例流跟踪仅限于直接 `x = Class(...)` 模式。
- 星号重新导出 (`from .x import *`) 不会被扩展。
将发现视为 **高信号指导**,并将发现的缺失视为“未被证明是不安全的”,而不是保证。
---
## 开发
```bash
git clone https://github.com/appcreationsca/bumpguard-mcp
cd bumpguard-mcp
python -m venv .venv && . .venv/Scripts/activate # Windows
pip install -e ".[dev]"
pytest
```
测试套件(42 个测试)使用固定包离线运行 - 无需网络。
### 发布
发布版本通过 GitHub Actions 自动进行。要发布版本:
1. 在 `pyproject.toml` 和 `src/bumpguard/__init__.py` 中更新版本号。
2. 将 `CHANGELOG.md` 中的“未发布”注释移动到新的版本标题下。
3. 提交,然后标记并推送:
```bash
git tag v0.1.0
git push origin v0.1.0
```
**发布** 工作流运行测试,构建轮子和 sdist,并发布到 PyPI via **Trusted Publishing** (OIDC - 没有存储令牌)。**CI** 工作流在每次推送和 PR 上运行测试矩阵(Linux + Windows,Python 3.10/3.13)。
---
## 许可证
MIT - 请参阅 [LICENSE](LICENSE)。