关于 mcp-bifrost
MCP-Bifrost 是面向 PHP 和 Python 的代码改写 MCP 服务,将已拆分的代码块交给工作模型处理,并在写入前执行校验。它适合批量机械性修改,通过原子应用和 Git 回滚记录避免不合语法的结果落盘。
主要功能
- 01解析并提取 PHP、Python 目标代码块
- 02将单个代码块委派给工作模型改写
- 03写入前检查偏移、语法和符号数量
- 04通过原子替换应用修改
- 05使用 Git blob 记录并支持回滚
适用场景
- 01批量改写许多已识别的方法
- 02将机械性代码生成交给较小模型
- 03在写入前拦截语法错误的改动
- 04通过历史记录恢复代码修改
MCP 相关
作为 MCP 服务,它向 MCP 客户端提供代码块改写、验证和应用工具;工作模型只接收目标代码块与指令。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
uvx mcp-bifrostDEEPSEEK_API_KEY密钥Worker API key. Not needed when BIFROST_WORKER_BASE_URL points at a local endpoint.BIFROST_WORKER_BASE_URLOpenAI-compatible endpoint for the worker model. Set this to run a local model so no code leaves the machine.BIFROST_WORKER_MODELWorker model identifier. Defaults to deepseek-chat.BIFROST_DBPath to the operational log. Defaults to .bifrost/history.db in the working directory.本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
MCP-Bifrost
用廉价模型重写 200 个方法,让结果中的任何一行都不会经过昂贵模型的上下文——并且不会将任何无法编译的内容写入磁盘。
一个 MCP 服务,接收编排模型已经分析并拆分好的代码任务,使用语言自身的解析器提取精确的目标代码块,将重写工作交给更廉价的工作模型,验证结果,以原子方式应用修改,并在编排模型上下文之外记录整个过程。
决策由大脑负责,敲代码由肌肉负责。Bifrost 是两者之间的神经——也是确保损坏内容不会写入磁盘的部分。
在下方示例中,大脑是 Claude,肌肉是 DeepSeek,它只是当时现成可用的模型。这两者都不是必需条件。关于为什么在自己的机器上运行 7B 模型可能更有意思,请参阅工作模型。
为什么
由 LLM 编辑大型代码库时,真正的瓶颈只有一个,而且不是智能:而是上下文。为了修改其中三十行代码而阅读一个 4,600 行的文件,会耗尽编排模型的上下文窗口,而那些文本之后再也用不上。
Bifrost 的前提是,编码中机械性的部分——编写替换文本——不需要昂贵的模型,也完全不需要经过它的上下文。
| 编排模型包办一切 | 通过 Bifrost | |
|---|---|---|
| 202 个方法 × 约 800 个 tok | 约 161,000 个 tok — 超出上下文窗口 | 约 15,000 个 tok |
实话实说(参见 RF-4):对于单个小型修改,节省确实存在,但幅度有限,因为编排模型通常必须先阅读代码,才能说明想要什么。数量级上的收益来自批量操作——对许多符号进行转换,而且无需阅读任何内容就能写出指令。
这正是它的设计用途,而不是“修复这个错误”。
日志报告的数字是一个反事实。 本仓库中的测试套件就是通过 Bifrost 编写的:应用了 97,909 字节的内容,指令只有 1,608 字节,按公式计算得出的比例为 61×。实际节省为零,因为这些代码块由编排模型而非工作模型编写,而在 Bifrost 看到它们之前,每个字节都已付出成本。日志记录的是跨越边界的内容,而不是内容由谁编写。示例详解见 §11,特意保留了不太好看的一面。
何时不该使用
- 探索性工作。“找出崩溃的原因”不是 Bifrost 能执行的指令。它需要在开始前知道相关符号。
- **单处小幅修改。**令牌数量的收益微乎其微,我们也明确说明了这一点 (RF-4)。请使用 Agent 常用的编辑工具。
- **对延迟敏感的循环。**每个代码块约需 2.6 秒,这是对照 DeepSeek 测得的。
- **任何非 PHP 或 Python 的语言。**添加一种语言只需编写解析器适配器,无需重写核心——但目前还不支持。
- 某处编辑的形式取决于另一处编辑结果的跨文件重构。
patch_group提供原子性,不提供顺序控制。 - **没有办法告知你发生错误的代码库。**这里的每道关卡都只检查形式,不理解含义。
关于它与 Aider、Serena 和快速应用模型的配合方式——包括它们更胜一筹的场景——请参阅docs/comparison.md。
工作原理
you ──▶ Claude Code ──▶ MCP-Bifrost ──▶ worker model
analyses, parses, writes one
splits work validates, isolated block
applies, logs
│
├──▶ source file (atomic splice)
└──▶ .bifrost/history.db
编排器决定做什么以及如何做。工作器不做任何决定。只有服务端可以操作磁盘,并且在所有关卡通过之前,它会拒绝操作。
验证关卡
| 关卡 | 检查内容 | 默认状态 |
|---|---|---|
| 0 — 偏移量 | 磁盘上的代码块与发送给工作器的内容逐字节相同 | 开启 |
| 1 — 语法 | 重建后的文件通过 php -l / ast.parse() 检查 | 开启 |
| 2 — 单个符号 | 返回的代码块恰好定义一个符号——类无论包含什么都算一个 | 开启 |
| 3 — 实质内容 | 没有调用、变量或控制关键字被悄然删除 | 关闭 |
**默认开启的是三道关卡,而不是四道。**实质内容关卡使用粗略的正则表达式检查,在校准期间从未触发过。会拒绝有效补丁的关卡,还不如暂不启用的关卡。批量操作前,可通过 substance_gate=True 启用它。
曾指定并实现过一种“边界检查”,用于比较目标范围之外的字节,但之后已删除:服务端通过 original[:start] + block + original[end:] 重建文件,因此边界自然得以保留,检查永远不会失败。校准结果也证实了这一点——尽管有三个文件仍存在语法错误,该关卡却报告了 9/9。参见RF-1。
回滚
Git 本身就是内容寻址数据库,因此这里直接将其用作数据库。每次补丁应用前运行 git hash-object -w,生成写入日志的 blob SHA;回滚时运行 git cat-file blob。自动去重并压缩,无需额外付费;可在工作区有未提交更改时使用,也无需维护专门的快照格式。
工作器
DeepSeek 是当时手头可用的模型,本仓库中的所有数据都是以它为基准测得的。这并非硬性要求,而且这可能也不是最有意思的运行方式。
工作器的职责刻意设得很窄。它接收一个独立代码块和一条指令,并返回一个代码块。它不会选择文件、规划修改、决定要编辑什么,也看不到代码库中的其他内容。这是一个 7B 编码模型能够胜任的任务——而设置这些关卡,正是为了在弱工作器的错误落盘之前将其拦截,而不是等到错误已经落盘后才发现。
因此,本地运行的优势更令人信服:
- 你的代码永远不会离开本机。 对于专有代码库,这不是偏好,而是前提。
- 针对本工具的工作负载,成本为零;一次运行处理数百个代码块很常见,而不是极端情况。
- 上下文需求很小。 一个方法,而不是一个文件。8k 的上下文窗口绰绰有余;整个设计的核心就是让工作器只看到它所需的内容。
- 只要每个输出都会先经过解析、语法检查和差异比对,弱工作器也完全可以胜任。 代码块出错只需重试,不会导致文件损坏。
最后这一点才是关键论据。通常不应该把代码生成交给小型本地模型,因为你无法信任其输出,而手动检查的成本又高于自己动手编写。Bifrost 的做法是让检查过程机械化,并交由机器完成。
任何兼容 OpenAI 的端点都可以使用——Ollama、llama.cpp 的服务端、LM Studio、vLLM:
"env": {
"BIFROST_WORKER_BASE_URL": "http://localhost:11434/v1",
"BIFROST_WORKER_MODEL": "qwen2.5-coder:7b"
}
如果使用的不是默认端点,则无需密钥。
工作器兼容性
目前尚未对任何本地模型进行测量。 端点可配置,协议也只是普通的 OpenAI 兼容聊天补全接口,但本仓库不会发布未经测量的说法——包括对自己有利的说法。
测量工具已经准备就绪。将它指向你的端点:
BIFROST_TARGET=/path/to/your/codebase \
BIFROST_WORKER_BASE_URL=http://localhost:11434/v1 \
BIFROST_WORKER_MODEL=your-model \
python3 calibratge/calibra.py --cases 9
| 工作器 | 有效 JSON | 字节完全一致(恒等任务) | 未丢失行数 | 未加围栏 | 延迟 |
|---|---|---|---|---|---|
DeepSeek(deepseek-chat,API) | 9/9 | 3/3 | 3/3 | 9/9 | 2.6 s |
| 在此填写你的模型 |
如果你运行了测试,请提交一个包含该行数据的 PR。让模型表现不佳的数据和让模型表现良好的数据一样有用——这张表旨在说明哪些工作器确实适用于此处,而不是用于宣传。
有一点值得注意。 DeepSeek 的九次响应中没有一次带有 Markdown 围栏。较小的模型几乎总会加上围栏,这属于解析问题,而非能力问题。Bifrost 已经会移除围栏;如果你的模型其他方面表现良好,却仍因围栏而失败,请在此处将其作为 bug 报告,而不要把它算作模型的缺点。
离开本机的内容
发送给工作器的工作单元是一个已解析的代码块——单个方法,而不是它所在的文件。这是设计使然,而非后来添加的功能:替换代码如果没有经过编排器的上下文,就不会通过其他任何途径传出。
这并不意味着什么。 代码块确实会以明文形式发送到你配置的任何端点。指令也会发送,而指令本身可能会描述内部架构。
现有的防护措施。 Heimdall 在发送之前运行,而不是在写入之前运行。对于独立成形的密钥,它会将其替换为占位符,工作器转换其周围的代码,然后在写入文件前还原原始密钥——每个占位符都必须恰好返回一次,否则什么也不会写入。无法安全脱敏的内容会直接阻止发送。在真实代码库中测得的误报率:1,291 个符号中有 2 次发现,且两次都正确拒绝了操作密钥而非持有密钥的代码。这个统计来自 0.1.0,当时符号映射仅包含方法和函数;类在 0.1.4 中才变得可寻址,因此如今重新统计时分母会更大。
如果你的要求是任何内容都不能离开本机,答案是使用本地工作器,而不是缩小负载。
设计已定,尚未实现
两项改进就能弥补大部分剩余差距。它们目前都尚未实现;在这里说明,而不是藏在 issue 里,是因为设计本身才是有趣之处:
- 出站日志。 日志记录发送内容的大小,而不是字节内容。把它们与返回内容一起记录几乎不费成本,而且能把“请相信我们”变成“可以审计”。
- 注释和字面量脱敏。 Heimdall 会脱敏形似密钥的内容。解析器已经生成了语法树,因此可以把注释和字符串字面量——它们往往是风险最高的负载,而且经常与转换无关——替换为不透明标记,并在返回时还原。
对第二项最显而易见的异议是:工作器看不到名称时,质量可能会下降。这是一个可以衡量的问题,而不是论据:使用脱敏的 9 个案例,不使用脱敏的 9 个案例,calibratge/calibra.py。无论结果如何,都会公布。
快速开始
Python 3.11+。无运行时依赖——服务使用标准库运行,每种语言都由其官方工具解析(php 是外部二进制文件,ast 来自标准库)。
pipx install mcp-bifrost # or: uv tool install mcp-bifrost
将其添加到你要修改的项目中的 .mcp.json:
{
"mcpServers": {
"bifrost": {
"command": "mcp-bifrost",
"env": { "BIFROST_DB": ".bifrost/history.db" }
}
}
}
客户端只按名称列出工具时,很容易在任务过程中忘记它们。 延迟加载工具架构的 MCP 客户端会将 Bifrost 的工具显示为纯名称,直到有人请求它们;而反复进行五次相同的机械编辑,本身并不会触发任何提示——这正是最初六个月内部试用的情况:insert_case 整个会话都无人使用,同一种 switch-case 模式却被反复手动编辑,随后两次并行编辑发生冲突,而这正是 insert_case 的锚定机制旨在避免的。一次性弥补这个项目中的缺口:
mcp-bifrost init-hook # writes .claude/settings.json in this project
mcp-bifrost init-hook --global # or: ~/.claude/settings.json, for every project
这会在 Edit/Write 上添加一个 PreToolUse hook,提醒客户端在手动编辑前检查是否有合适的 Bifrost 工具——以增量方式添加,因此你已有的任何 hook 都会保留。你可以随时再次运行;hook 已存在时不会执行任何操作。提交项目级 .claude/settings.json,让这条提醒随仓库一同保留,而不只是存在于某一台机器上。
事实证明,仅有提醒并不足够——安装并触发了 50 多次 hook 的完整构建会话中,96% 的新文件仍通过原始 Write 创建(见 docs/critical-review.md,RF-13)。后来的一个会话解决了这个问题:被直接问到时,客户端承认自己没有使用这些工具,于是加载了它们,调用了一次,随后仍然手动编辑了一个新的 switch case、两个新函数和两处方法重写,尽管每次编辑都触发了提醒。已经读过并表示认同的文字,并不会改变下一次决策。
因此,hook 会直接阻止以下两种情况:
- 对该服务适配的现有文件执行
Edit或Write(.php、.py),且所在项目的.mcp.json注册了bifrost。针对每种代码结构,拒绝消息都会指出对应的工具——insert_case、insert_symbol、fix_symbol、fix_symbols、fix_range、patch_group。 - 通过
Write创建尚不存在的文件,且所在目录中已有三个或更多扩展名相同的同级文件;此时会提示使用create_file(model_from=<nearest sibling>)。
其他情况仍仅给出提示。第一个检查门会从磁盘读取作用范围,因此使用 --global 是安全的:从未配置此服务的项目中的 .php 或 .py 文件绝不会被阻止。如果编辑确实没有可定位的符号,执行 touch .bifrost/hook-override 即可放行下一次编辑——该标记会在使用时被消耗,因此只放行一次编辑,而不是让整个会话悄悄退出限制。
如果你开发此服务,请从 main 工作树安装钩子
这个钩子是强制执行的、全局的,而且以可编辑模式从你的开发检出安装后,它运行的就是该检出当前所在分支上的内容。切换到功能分支,就会悄无声息地改变这台机器上所有其他项目的检查门槛,而这正是此工具旨在消除的那类意外。请保留一个固定在 main 的第二工作树,并改为从那里安装:
git worktree add ../MCP-Bifrost-main main
pipx install --force --editable ../MCP-Bifrost-main
你可以在原始检出中继续开发,无论在哪个分支,都不会影响正在运行的钩子。合并到 main 后,再有意更新工作树:
git -C ../MCP-Bifrost-main pull # editable install: no reinstall needed
对于任何通过路径启动服务的 .mcp.json,也同样适用:将其 PYTHONPATH 指向 main 工作树,而不是你进行开发的检出。
或者直接从源代码运行,不安装:
git clone https://github.com/FixemBCN/MCP-Bifrost.git
cd MCP-Bifrost
python3 -m unittest discover tests # 308 tests, ~32s
python3 -m mcp_bifrost.server # same server, PYTHONPATH=.
**如果你的 PATH 中没有 php,你会看到 OK (skipped=80),**这正是预期结果:这 80 项测试会调用真正的 PHP 分词器,所以在没有 PHP 的机器上,它们无从验证。其余 228 项测试——检查门槛、补丁器、预算、Heimdall、Python 适配器——只依赖标准库。如果你想在自己的机器上验证 PHP 部分,请安装 php-cli;CI 会在每次推送时测试这两种环境。git 也以同样的方式控制 91 项测试。
不要把密钥放在那个文件中。 请将它放在项目根目录下的 .bifrost.env 中;当环境变量中没有密钥时,服务会从该文件读取:
echo "DEEPSEEK_API_KEY=sk-..." > .bifrost.env
chmod 600 .bifrost.env
echo ".bifrost.env" >> .gitignore
或者完全跳过密钥,并将 BIFROST_WORKER_BASE_URL 指向本地模型。完整说明,以及在将其用于任何重要用途前需要采取的措施,请参阅手册。
工具
| 工具 | 功能 |
|---|---|
fix_symbols | 用一条指令处理多个符号——主要工具 |
fix_symbol / fix_range | 重写一个符号或指定的行范围——可选的 verify 命令,失败时回滚 |
insert_symbol / insert_case | 添加函数、方法或类,或者为 switch 路由器添加分支 |
create_file | 创建新文件,可参照现有文件——可选的 verify 命令,失败时删除 |
patch_group | 将多个操作作为一个事务执行 |
export_docs / publish_session | 根据日志生成变更日志;将多个更改批量提交到可审查的分支 |
revert_patch / revert_session | 撤销单个补丁或整个批次 |
校准
编写服务中的任何代码之前,必须先回答一个问题:
给定一个来自真实代码库的真实方法,并使用紧凑模式打包后,工作器是否能返回可应用且不会造成破坏的代码?
calibratge/ 中的测试框架给出了答案。零依赖——Python 标准库加上 php 二进制文件。
export BIFROST_TARGET=/path/to/your/codebase
python3 calibratge/calibra.py --dry-run # show cases, no API calls
export DEEPSEEK_API_KEY=...
python3 calibratge/calibra.py --cases 9
结果:假设成立。 有效 JSON 为 9/9;身份任务字节完全一致为 3/3;原始行无一丢失为 3/3;没有任何结果被 Markdown 代码围栏包裹,为 0/9;平均延迟为 2.6 秒。
它还捕获了一个与工作器毫无关系的字节偏移错误;这个错误会在生产环境中悄无声息地损坏文件。完整说明请参阅:docs/calibration.md。
仓库布局
| 路径 | 内容 |
|---|---|
mcp_bifrost/ | 服务 |
CHANGELOG.md | 各个版本的变更内容,以及之前出错的原因 |
docs/ | 手册、架构、批判性评审、校准、比较、许可 |
tests/ | 308 项测试——其中 80 项需要 php,91 项需要 git,缺少时会跳过 |
brainstorm/ | 工作记录——每项决策的形成过程,包括后来被推翻的决策 |
calibratge/ | 测量工具 |
.github/ | 徽章所报告的工作流:在有 php 的情况下运行测试套件,再在没有 php 的情况下运行一次 |
代码背后
完全坦诚地说:这个代码库没有一行是手工编写的。 它是在人工指导下,经过 AI 流程构思、质疑、实现、测试和编写文档的。下面会尽可能准确地说明这实际上意味着什么。
人类——问题、决策、方向。 我提出了初始规范,并做出了所有产品决策:采用哪种工作模型、支持哪些语言、删掉什么、接下来构建什么、选择哪种许可、如何命名,以及何时停止。其中有几项推翻了早先的决定——最初采用的是禁止转售的源代码可用许可,后来我认为覆盖面比控制权更重要,于是改为 Apache-2.0。我还决定了系统必须拒绝做什么,而这最终成了影响更大的一半。
Claude Opus——对抗性设计评审。 在实现之前,Claude 以局外人的视角审查规范,寻找可能导致失败的理由,并提出了十二项发现。其中两项否定了我已批准的设计要素:规范依赖的中央“边界检查”实际上不可能失败;项目声称的理由——节省 token——对于单次编辑效果有限,只有在批量操作时才起决定性作用。这些内容未经修改地保存在 brainstorm/ 中。
先测量,再写代码。 我们没有盲信设计,而是先构建校准工具,并用真实代码对真实工作模型进行测试。9 个案例中有 6 个失败了——没有一个是工作模型的问题。原因是字节偏移错误,它会悄无声息地破坏任何包含重音字符的文件。校准还驳斥了 Claude 自己评审结论中的两项。这些修正被置于原始结论之上,而不是用来取代它们。
Claude Opus——核心;委派模型——外围。 Claude 直接编写了解析、补丁处理、验证关卡、机密处理和引擎。两个外围模块和整套原始测试套件则委派给较小的模型(Haiku 和 Sonnet),以子 Agent 的形式运行。此后测试套件大致扩充了一倍:0.1.2–0.1.5 中新增的测试由 Opus 编写,并通过 Bifrost 本身应用;之所以需要这些测试,是因为原有的 128 项测试从未实际运行过 MCP 服务、工作模型的 HTTP 客户端、VCS 层或 Python 适配器。这样的分工是有意为之,而非出于节省成本的考虑:一个对补丁处理代码毫无背景的模型极有可能重新引入字节偏移错误,因为编写这类代码时最自然的做法恰恰是错误的做法。
委派模型在 Claude 编写的代码中发现了四个真实错误,其中一个会使文档块脱离它所说明的方法,另一个会导致嵌套的 switch 语句悄无声息地丢失分支。这两个错误都通过了所有验证关卡。只有让一个与代码毫无利害关系的模型进行对抗性评审,才发现了它们。
人类——评审与验收。 我指导了整个流程,检查结果、质疑结论,并决定保留什么。Claude 执行了验证和校准;我阅读返回的结果,并决定它们意味着什么。
此过程未能提供什么
没有人逐行读完本仓库全部约 10,700 行代码——其中约 4,600 行是服务端代码,5,400 行是测试代码,700 行是测量工具代码。这里的可信度来自针对故意破坏的代码运行测试、基于真实代码库进行测量,以及一项拒绝写入任何无法验证内容的设计,而非人工审查。
如果你不愿意将这种可信度视为编辑源文件的工具所应具备的保障,这是合理的立场;责任说明具体说明了这些关卡能和不能检测什么。
为什么 README 中会写这些
Bifrost 展示了它自身理念的实践。人类的宝贵贡献并非敲代码,而是定义问题、控制上下文、质疑输出,并坚持进行充分验证,让生成的代码真正值得信赖。
本仓库特意保留了推理过程、被否决的想法、对抗性审查和测量结果——包括 AI 出错并承认错误的部分。
**这份记录止于首次发布,但工作并未止步。**此后发生的事情记录在 CHANGELOG.md 中,其中逐一记录了发现的缺陷,以及它们此前如何一直未被察觉;此前设计的形成过程则记录在 brainstorm/ 和 docs/critical-review.md 中。
文档
| 文档 | 内容 |
|---|---|
| 手册 | 介绍它是什么、能做什么、如何安装,以及你需要承担什么责任 |
| 架构 | 说明构建什么以及原因 |
| 批判性审查 | 以全新视角寻找可能导致失败的原因——共发现 12 个问题,其中两个后来经测量证伪 |
| 校准结果 | 说明工作器在收到要求后实际做了什么 |
| 比较 | 说明它与 Aider、Serena 和 fast-apply 的异同,以及它们胜出的方面 |
| 许可 | 说明我们使用了什么,以及授予了什么 |
brainstorm/ 保存了工作记录:原始规范、历经五次修订的设计日志、对抗性审查和校准结果。如果两者存在差异,应以 docs/ 中的内容为准。
责任
此工具会使用语言模型自动编辑你的源文件。Apache 2.0 意味着它按原样提供,不附带任何保证:你需要对它对代码造成的影响负责。检查差异,运行测试,并谨慎部署。手册具体说明了这些关卡能和不能检测什么。
贡献
欢迎以任何形式贡献——包括指出这里的内容有误。本项目已经删除了一个同义反复的验证关卡,并通过测量证伪了自己的两个主张。
只有一条约定,而且至关重要:**每项测试都必须有可能失败。**详情请见手册。
许可证
基于 Model Context Protocol 构建,该协议由 Anthropic, PBC 以 MIT 许可证授权。MCP-Bifrost 是一个独立项目,与 Anthropic, PBC 无关,也未获得其认可或赞助。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。