内容
# bazel-mcp
[](https://github.com/ewhauser/bazel-mcp/actions/workflows/ci.yml)
[](LICENSE)
在无需填充构建日志的上下文窗口的情况下,从与MCP兼容的编码代理运行Bazel。
`bazel-mcp`是一个本地的[模型上下文协议](https://modelcontextprotocol.io/)服务器。它在您的工作区中运行Bazel,返回一个简洁的 actionable 结果,并为代理保留完整的调用证据,以便在需要更多详细信息时进行检查。
## 为什么选择bazel-mcp?
Bazel的输出可能非常庞大。向编码代理发送完整的进度输出、重复的警告和测试日志会浪费上下文,并可能隐藏重要的错误。
`bazel-mcp`为代理提供:
- 成功和失败调用的简洁摘要;
- 结构化的诊断、测试结果、覆盖率、工件、查询输出;
- 保留证据的过滤、分页访问;
- 取消排队或正在运行的命令。
Bazel仍然在您的工作区中本地运行,配置了凭据、工具链和远程执行设置。
## 快速入门
### 要求
- macOS 或 Linux
- Bazel 7、8 或 9、Bazelisk 或可执行的工作区本地 `tools/bazel`
- 与MCP兼容的客户端
- 从源代码构建时,Rust 1.94.1
### 使用Homebrew安装
```sh
brew install ewhauser/tap/bazel-mcp
```
### 从发布版本安装
从[最新的GitHub发布版本](https://github.com/ewhauser/bazel-mcp/releases/latest)下载预构建的存档,或在macOS或Linux上运行shell安装程序:
```sh
curl --proto '=https' --tlsv1.2 -LsSf \
https://github.com/ewhauser/bazel-mcp/releases/latest/download/bazel-mcp-installer.sh | sh
```
### 从源代码构建
克隆仓库并使用固定的Rust工具链构建服务器:
```sh
git clone https://github.com/ewhauser/bazel-mcp.git
cd bazel-mcp
cargo build --release -p bazel-mcp-server
```
二进制文件被写入 `target/release/bazel-mcp`。
### 连接您的MCP客户端
将二进制文件注册为stdio MCP服务器。确切的设置位置取决于您的客户端。
```json
{
"mcpServers": {
"bazel": {
"command": "bazel-mcp"
}
}
}
```
如果您在构建时没有安装二进制文件,请使用 `target/release/bazel-mcp` 的绝对路径代替。
重启客户端,打开一个Bazel工作区,并尝试以下提示:
- “构建 `//app:server`。”
- “运行 `//services/...` 下的测试并解释任何失败。”
- “哪些目标依赖于 `//lib:core`?”
不需要配置文件。默认情况下,服务器可以在当前用户可访问的任何工作区中运行Bazel。参见 [安全性和本地数据](#安全性和本地数据) 以限制特定的根目录。
## 工具
服务器暴露了三个工具:
| 工具 | 目的 |
| --- | --- |
| `bazel.run` | 运行允许的Bazel命令并返回有界摘要。 |
| `bazel.inspect` | 读取调用的过滤诊断、测试、覆盖率、工件、查询结果或日志。 |
| `bazel.cancel` | 取消排队或正在运行的调用。 |
`bazel.run` 支持 `build`、`test`、`coverage`、`query`、`cquery`、`aquery` 和选定的信息命令。成功的结果限制为 2 KiB,不成功的结果限制为 8 KiB。后续的 `bazel.inspect` 调用也是有界和分页的,因此代理只检索需要的证据。
长时间调用可以在MCP客户端声明任务支持时作为持久任务句柄返回。默认情况下,服务器会发现协商的协议并选择同步执行、MCP `2025-11-25` 旧任务或 `io.modelcontextprotocol/tasks` 扩展在运行时。这不会添加工具:任务状态、结果和取消是协议方法。
## MCP协议形状
MCP客户端通常代表代理生成这些消息,但在集成或调试主机时,线路形状非常有用。`bazel-mcp` 使用stdio上的换行分隔的JSON-RPC 2.0;下面的示例为了可读性而跨行格式化,并省略了无关的响应字段。
| 流 | 客户端信号 | 初始结果 | 最终结果 |
| --- | --- | --- | --- |
| 同步 | 无任务能力,或 `sync_only` 策略 | `CallToolResult` | 相同的 `tools/call` 响应 |
| 旧任务 | MCP `2025-11-25` 加 `params.task` | 嵌套 `result.task` | 单独的 `tasks/result` 调用 |
| 任务扩展 | 请求 `_meta` 中的扩展能力 | 平坦的 `resultType: "task"` | 终端 `tasks/get` 中的内联 |
<details>
<summary>显示代表性的JSON-RPC消息</summary>
### 同步调用
基本调用是一个普通的MCP工具请求:
```json
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "bazel.run",
"arguments": {
"workspace": "/src/project",
"command": "build",
"args": ["//app:server"]
}
}
}
```
如果没有兼容的任务选择,请求保持附加并返回正常的 `CallToolResult`。默认的 `text` 编码将有界的逻辑结果放在一个文本内容块中:
```json
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [{
"type": "text",
"text": "{\"invocation_id\":\"019f...\",\"state\":\"succeeded\",\"command\":\"build\",\"exit_code\":0,\"headline\":\"Build succeeded\",\"more_available\":true}"
}],
"isError": false
}
}
```
该 `invocation_id` 可以传递给 `bazel.inspect` 或 `bazel.cancel`。不同的结果编码会改变内容表示,而不是逻辑结果或其字节预算。
### 旧MCP任务
协商MCP `2025-11-25`的客户端会看到 `bazel.run.execution.taskSupport = "optional"`。它通过在相同的工具调用中添加 `params.task` 来选择分离执行:
```json
{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "bazel.run",
"arguments": {
"workspace": "/src/project",
"command": "test",
"args": ["//services/..."]
},
"task": {}
}
}
```
响应包含一个嵌套任务。它的 `taskId` 也是Bazel调用ID,并且在句柄返回后即可读取:
```json
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"task": {
"taskId": "019f...",
"status": "working",
"ttl": 86400000,
"pollInterval": 2000
},
"_meta": {
"io.modelcontextprotocol/related-task": {
"taskId": "019f..."
}
}
}
}
```
客户端轮询 `tasks/get`,等待原始 `CallToolResult` 与 `tasks/result`,列出具有 `tasks/list` 的持久句柄,或请求 `tasks/cancel`。
### 任务扩展
现代扩展感知客户端可以使用 `server/discover` 发现能力:
```json
{
"jsonrpc": "2.0",
"id": 4,
"method": "server/discover",
"params": {}
}
```
```json
{
"jsonrpc": "2.0",
"id": 4,
"result": {
"capabilities": {
"extensions": {
"io.modelcontextprotocol/tasks": {}
}
}
}
}
```
在协商扩展的 `2026-06-30` 基础协议后,每个参与请求在 `_meta` 中声明扩展。初始结果是平坦的,而不是嵌套的:
```json
{
"jsonrpc": "2.0",
"id": 5,
"method": "tools/call",
"params": {
"name": "bazel.run",
"arguments": {
"workspace": "/src/project",
"command": "build",
"args": ["//app:server"]
},
"_meta": {
"io.modelcontextprotocol/clientCapabilities": {
"extensions": {
"io.modelcontextprotocol/tasks": {}
}
}
}
}
}
```
```json
{
"jsonrpc": "2.0",
"id": 5,
"result": {
"resultType": "task",
"taskId": "019f...",
"status": "working",
"ttlMs": 86400000,
"pollIntervalMs": 2000
}
}
```
这里,客户端轮询 `tasks/get`;一旦终端,该响应将原始 `CallToolResult` 内联在其 `result` 字段中。扩展没有 `tasks/result` 或 `tasks/list` 方法。两种任务方言在服务器重启时都是持久的,而声明两者都不的客户端继续使用更简单的同步形状。
</details>
参见 [specification 003](specs/003-configurable-mcp-task-execution.md) 获取完整的协商矩阵、取消语义、错误代码和固定的协议修订。
## 安全性和本地数据
`bazel-mcp` 以启动MCP客户端的用户权限执行Bazel。它不使不受信任的存储库安全;请为不受信任的源使用沙箱或隔离帐户。
服务器:
- 直接调用Bazel,而不进行shell评估或连接参数;
- 默认拒绝 `clean`、`fetch`、`mobile-install`、`run`、`shutdown` 和 `sync`;
- 防止请求覆盖服务器拥有的BEP和输出根标志;
- 过滤子进程环境并支持可配置的正则表达式编辑;
- 仅在本地缓存中存储原始输出和BEP证据,使用私有文件权限。
要将服务器限制到一个或多个工作区根目录,请在MCP配置中添加重复的 `--allow-root` 参数:
```json
{
"mcpServers": {
"bazel": {
"command": "bazel-mcp",
"args": ["--allow-root", "/absolute/path/to/workspaces"]
}
}
}
```
参见 [SECURITY.md](SECURITY.md) 获取安全策略和威胁模型指导。
## 配置
内置的默认值涵盖个人本地使用。对于工作区限制、保留限制、超时、命令策略、结果编码或自定义编辑,请从 [`examples/config.toml`](examples/config.toml) 开始。
使用 `--config` 显式传递配置,设置 `BAZEL_MCP_CONFIG`,或将其放在 `$XDG_CONFIG_HOME/bazel-mcp/config.toml`(通常为 `~/.config/bazel-mcp/config.toml`)。命令行选项还可以添加允许的根目录或覆盖缓存目录。
参见 [配置参考](docs/configuration.md) 获取所有设置及其默认值。
## 兼容性
| 组件 | 支持 |
| --- | --- |
| Bazel | 主要版本 7、8 和 9 |
| 平台 | macOS 和 Linux |
| 传输 | 本地MCP通过stdio |
| Bazel发现 | `tools/bazel`,然后是Bazelisk,然后是`PATH`上的Bazel |
| 任务执行 | 同步回退,MCP `2025-11-25` 旧任务和SEP-2663任务扩展 |
除非在配置中明确启用,否则其他Bazel主要版本在创建调用之前会被拒绝。
如果主机无法使用任务形状的结果,请使用 `mcp_execution_policy = "sync_only"`。仅当需要分离执行时,才使用 `tasks_required`;否则,来自没有兼容能力的客户端的调用将在Bazel启动前被拒绝。有关TTL和轮询设置的更多信息,请参见 [配置参考](docs/configuration.md#configure-negotiated-task-execution)。
## 性能
### 确定性调用基准
在针对固定Abseil语料库的三个独立五样本运行中,`bazel-mcp` 与默认shell代理相比,减少了累计模型上下文 89.73–90.69%。最新的运行测量了 89.73% 的减少,0.00% 的中位数配对Bazel墙时间开销。
这些结果是确定性的令牌估计,而不是提供商计费。参见 [基准测试方法](docs/benchmarks.md) 获取完整的结果、语料库、验收门和复制命令。
### 代理编码基准
在两个高输出Abseil编码任务的五样本运行中,`gpt-5.6-luna` 在 `xhigh` 推理方面解决了所有10次尝试。与直接shell Bazel相比,`bazel-mcp` 在缓存输入权重为零时,减少了提供商报告的总令牌 **36.88%** 和活动令牌 **41.77%**。
| 指标 | Shell Bazel | `bazel-mcp` | 减少 |
| --- | ---: | ---: | ---: |
| 验证解 | 10/10 | 10/10 | 相同 |
| 总令牌 | 2,444,393 | 1,542,870 | 36.88% |
| 活动令牌,0%缓存输入权重 | 479,593 | 279,254 | 41.77% |
| 代理时间 | 653.2s | 637.1s | 2.46% |
比较包括MCP模式和工具调用开销。参见 [签入的代理基准测试报告](docs/agentic-benchmark-report.md) 获取任务级别的结果、缓存敏感性、完整性检查和限制,或 [代理基准测试方法](docs/benchmarks.md#agentic-coding-benchmark) 复制它。
## 贡献
欢迎贡献。通常的本地检查是:
```sh
make build
make test
make check
```
运行器、BEP、策略或减速器更改还应运行 `make test-bazel-matrix`。在打开拉取请求之前,请阅读 [CONTRIBUTING.md](CONTRIBUTING.md)。
架构和协议决策记录在 [`specs/`](specs/) 下。
## 许可证
`bazel-mcp` 在 [MIT License](LICENSE) 下可用。