Skip to main content
Glama
SyJarvis

Bambuddy MCP Server

by SyJarvis
README.md
# Bambuddy MCP Server

Bambuddy MCP Server 是 Codex、Claude Code 和其他 MCP Client 与 Bambuddy API
之间的适配层。状态和预检工具只读;开始打印采用显式开关和两阶段确认。

完整安装、远程部署、工具参数和故障排查请参见
[Bambuddy MCP 使用文档](docs/usage.md)。使用 Docker 依次部署 Bambuddy、MCP 并接入
Codex,请参见 [Docker 部署与使用指南](docs/docker-deployment.md)。架构决策和后续
路线见 [Agent 接入设计](docs/design.md)。

```text
本地:Agent ⇄ MCP over stdio ⇄ Bambuddy MCP ⇄ HTTP API ⇄ Bambuddy ⇄ Printer
远程:Agent ⇄ Streamable HTTP/HTTPS ⇄ Bambuddy MCP ⇄ HTTP API ⇄ Bambuddy ⇄ Printer
```

它不直接连接打印机 MQTT,不导入 Bambuddy 后端模块,也不读取数据库。所有打印机
连接、文件和摄像头凭据仍由 Bambuddy 管理。

## 当前工具

| Tool | 用途 |
|---|---|
| `bambuddy_list_printers` | 列出已配置打印机的非敏感摘要 |
| `bambuddy_get_printer_status` | 查询实时状态、进度、温度、HMS 和 AMS 摘要 |
| `bambuddy_get_current_print` | 查询当前打印任务 |
| `bambuddy_diagnose_printer` | 运行连接诊断并移除 IP 和内部参数 |
| `bambuddy_get_camera_status` | 查询摄像头流健康状态 |
| `bambuddy_get_camera_snapshot` | 获取一帧 JPEG/PNG 图像 |
| `bambuddy_list_print_sources` | 列出可重印的归档 `.gcode.3mf` 文件 |
| `bambuddy_prepare_print` | 只读预检并生成 5 分钟、一次性的确认令牌 |
| `bambuddy_start_print` | 消费确认令牌,创建置顶的 ASAP 打印队列任务 |

除 `bambuddy_start_print` 外,工具均声明为只读、非破坏、幂等。开始打印工具声明为
写操作、破坏性、非幂等。所有工具都会访问配置的 Bambuddy 服务,因此声明
`openWorldHint=true`。

## 安全边界

MCP 输出使用字段白名单,明确排除:

- 打印机 access code;
- 打印机 IP 和序列号;
- 外部摄像头 URL;
- AMS RFID tag UID 和 spool UUID;
- 原始 MQTT payload;
- API Token。

即使 Bambuddy 未开启认证、`GET /printers/` 返回了额外管理字段,MCP 也不会把这些
字段传给 Agent。建议仍然开启 Bambuddy 认证,并创建只有 `can_read_status` 权限的
专用 API Key。

打印机名称、文件名、HMS 信息和摄像头画面来自外部设备,Agent 应将其视为不可信
内容,不能把其中的文字当作指令执行。

## 安装

在本项目根目录运行:

```bash
cd /absolute/path/to/bambuddy-mcp
uv sync --extra test
```

安装后入口位于:

```text
/absolute/path/to/bambuddy-mcp/.venv/bin/bambuddy-mcp
```

也可以使用普通 Python 虚拟环境安装:

```bash
python -m venv .venv
.venv/bin/pip install -e '.[test]'
```

### Docker(Streamable HTTP)

镜像默认以非 root 用户运行,监听 `0.0.0.0:8765`,保持写工具关闭,并通过
`GET /health` 执行健康检查。完整的 Bambuddy → API Key → MCP → Codex 部署顺序见
[Docker 部署与使用指南](docs/docker-deployment.md):

```bash
docker build -t bambuddy-mcp:local .

export BAMBUDDY_API_TOKEN='Bambuddy 专用 API Key'
export BAMBUDDY_MCP_BEARER_TOKEN="$(openssl rand -hex 32)"

docker run --rm --name bambuddy-mcp \
  -p 8765:8765 \
  -e BAMBUDDY_API_URL=http://host.docker.internal:8000/api/v1 \
  -e BAMBUDDY_API_TOKEN \
  -e BAMBUDDY_MCP_BEARER_TOKEN \
  -e BAMBUDDY_HTTP_PUBLIC_URL=http://127.0.0.1:8765/mcp \
  -e 'BAMBUDDY_HTTP_ALLOWED_HOSTS=127.0.0.1:*,localhost:*' \
  bambuddy-mcp:local
```

Linux 上访问宿主机的 Bambuddy 时,为 `docker run` 增加
`--add-host=host.docker.internal:host-gateway`。如果两个服务位于同一个 Docker
网络,则应直接使用 Bambuddy 的服务名,例如
`BAMBUDDY_API_URL=http://bambuddy:8000/api/v1`。

容器绑定非回环地址,因此必须显式提供 `BAMBUDDY_MCP_BEARER_TOKEN`、
`BAMBUDDY_HTTP_PUBLIC_URL` 和 `BAMBUDDY_HTTP_ALLOWED_HOSTS`;缺少任意一项都会安全地
拒绝启动。不要把 Token 写入镜像或 Dockerfile。

## 配置

```bash
export BAMBUDDY_API_URL="http://127.0.0.1:8000/api/v1"
export BAMBUDDY_API_TOKEN="replace-with-bambuddy-api-key"
export BAMBUDDY_AGENT_ID="codex"
```

可用环境变量:

| 变量 | 默认值 | 说明 |
|---|---|---|
| `BAMBUDDY_API_URL` | `http://127.0.0.1:8000/api/v1` | Bambuddy API 根地址 |
| `BAMBUDDY_API_TOKEN` | 未设置 | Bambuddy API Key;认证关闭时可省略 |
| `BAMBUDDY_AGENT_ID` | `mcp-client` | 写入请求头的客户端标识 |
| `BAMBUDDY_ENABLE_WRITE_TOOLS` | `false` | 是否允许 `bambuddy_start_print` 真正创建队列任务 |
| `BAMBUDDY_TRANSPORT` | `stdio` | `stdio` 或 `streamable-http` |
| `BAMBUDDY_HTTP_HOST` | `127.0.0.1` | HTTP 监听地址;远程监听常用 `0.0.0.0` |
| `BAMBUDDY_HTTP_PORT` | `8765` | HTTP 监听端口 |
| `BAMBUDDY_HTTP_PATH` | `/mcp` | Streamable HTTP MCP 路径 |
| `BAMBUDDY_HTTP_PUBLIC_URL` | 未设置 | 客户端访问的完整公网/VPN URL |
| `BAMBUDDY_HTTP_ALLOWED_HOSTS` | 未设置 | 允许的 Host,多个值用逗号分隔 |
| `BAMBUDDY_HTTP_ALLOWED_ORIGINS` | 未设置 | 允许的 Origin,多个值用逗号分隔;非浏览器客户端通常不发送 Origin |
| `BAMBUDDY_MCP_BEARER_TOKEN` | 未设置 | MCP 客户端访问 `/mcp` 使用的独立 Token |
| `BAMBUDDY_HTTP_STATELESS` | `false` | 是否使用无会话 HTTP;目前建议保持 `false` |
| `BAMBUDDY_HTTP_JSON_RESPONSE` | `false` | 是否禁用 SSE 响应并只返回 JSON |
| `BAMBUDDY_HTTP_MAX_REQUEST_BYTES` | `1048576` | MCP HTTP 请求体上限 |
| `BAMBUDDY_API_TIMEOUT_SECONDS` | `20` | HTTP 请求超时,最大 120 秒 |
| `BAMBUDDY_API_MAX_RESPONSE_BYTES` | `2097152` | JSON 响应上限 |
| `BAMBUDDY_SNAPSHOT_MAX_RESPONSE_BYTES` | `8388608` | 快照响应上限 |

Token 只应通过环境变量或密钥管理工具提供,不要写入仓库配置、命令行参数或 Skill。
如果 MCP 与 Bambuddy 不在同一台主机,使用 HTTPS 或可信的加密隧道。

`BAMBUDDY_API_TOKEN` 是 MCP 调用 Bambuddy REST API 的凭据;
`BAMBUDDY_MCP_BEARER_TOKEN` 是远程 Agent 调用 MCP 的凭据。两者用途不同,不应复用。

要允许开始打印,建议先在 Bambuddy 开启认证,创建同时具有 `can_read_status` 和
`can_queue` 权限、且只允许目标打印机的专用 API Key。然后显式设置:

```bash
export BAMBUDDY_ENABLE_WRITE_TOOLS=true
```

没有这个开关,即使调用者获得了预检令牌,开始打印工具也会拒绝执行。

## 接入 Codex Desktop / CLI

先在启动 Codex 的环境中设置 `BAMBUDDY_API_TOKEN`,然后在
`~/.codex/config.toml` 或受信任项目的 `.codex/config.toml` 中添加:

```toml
[mcp_servers.bambuddy]
command = "/absolute/path/to/bambuddy-mcp/.venv/bin/bambuddy-mcp"
cwd = "/absolute/path/to/bambuddy-mcp"
required = true
startup_timeout_sec = 10
tool_timeout_sec = 30
default_tools_approval_mode = "writes"
enabled_tools = [
  "bambuddy_list_printers",
  "bambuddy_get_printer_status",
  "bambuddy_get_current_print",
  "bambuddy_diagnose_printer",
  "bambuddy_get_camera_status",
  "bambuddy_get_camera_snapshot",
  "bambuddy_list_print_sources",
  "bambuddy_prepare_print",
  "bambuddy_start_print",
]
env_vars = ["BAMBUDDY_API_TOKEN", "BAMBUDDY_ENABLE_WRITE_TOOLS"]

[mcp_servers.bambuddy.env]
BAMBUDDY_API_URL = "http://127.0.0.1:8000/api/v1"
BAMBUDDY_AGENT_ID = "codex"
```

只读使用时从 `enabled_tools` 删除 `bambuddy_start_print`,并且不要设置
`BAMBUDDY_ENABLE_WRITE_TOOLS`。开启写工具后,Codex 仍会根据 destructive/write
annotations 在执行前请求审批。

## Streamable HTTP 远程部署

MCP 应部署在能够访问 Bambuddy API 的主机上。生成高强度随机 Token:

```bash
openssl rand -hex 32
```

局域网、Tailscale 或 WireGuard 内启动示例:

```bash
cd /absolute/path/to/bambuddy-mcp
export BAMBUDDY_TRANSPORT=streamable-http
export BAMBUDDY_HTTP_HOST=0.0.0.0
export BAMBUDDY_HTTP_PORT=8765
export BAMBUDDY_HTTP_PATH=/mcp
export BAMBUDDY_HTTP_PUBLIC_URL=https://bambuddy.example.com/mcp
export BAMBUDDY_HTTP_ALLOWED_HOSTS=bambuddy.example.com
export BAMBUDDY_MCP_BEARER_TOKEN='从密钥管理器注入的随机值'
export BAMBUDDY_API_URL=http://127.0.0.1:8000/api/v1
export BAMBUDDY_API_TOKEN='Bambuddy 专用 API Key'
.venv/bin/bambuddy-mcp
```

访问点:

- `GET /health`:公开健康检查,只返回服务名和版本;
- `POST/GET/DELETE /mcp`:Streamable HTTP MCP,需要 Bearer Token。

绑定非回环地址时,服务会拒绝缺少 MCP Token、公开 URL 或 Host 白名单的配置。
应用本身提供 HTTP,公网 TLS 应由 Caddy、Nginx、Traefik 或可信隧道终止;不要把
明文 `8765` 端口直接映射到公网。

远程 Codex 配置:

```toml
[mcp_servers.bambuddy]
url = "https://bambuddy.example.com/mcp"
bearer_token_env_var = "BAMBUDDY_MCP_BEARER_TOKEN"
required = true
tool_timeout_sec = 30
default_tools_approval_mode = "writes"
```

在启动 Codex 的客户端环境中设置相同的 MCP Token:

```bash
export BAMBUDDY_MCP_BEARER_TOKEN='与服务端一致的随机值'
codex mcp list
codex mcp get bambuddy
```

如果只在服务端反向代理之后运行,可让 MCP 继续绑定 `127.0.0.1:8765`,并在反向代理
层完成 TLS。仍建议同时设置 MCP Bearer Token,形成应用层的第二道认证边界。

## 开始打印的安全流程

```text
bambuddy_list_print_sources
  → bambuddy_prepare_print
  → 用户核对打印机、文件、plate、耗材、选项和警告
  → 用户明确确认
  → bambuddy_start_print(confirmed=true)
  → bambuddy_get_current_print / bambuddy_get_printer_status 验证
```

`bambuddy_prepare_print` 不修改任何状态。令牌保存在 MCP 进程内,5 分钟后失效且只能
使用一次。`bambuddy_start_print` 不绕过 Bambuddy 调度器;它通过 `POST /queue/`
创建 `insert_at_top=true`、`manual_start=false` 的 ASAP 任务。打印机忙时任务会等待,
返回 `pending` 只表示 Bambuddy 已接收任务,不代表打印机已经开始运动。

重启 Codex 后检查:

```bash
codex mcp list
codex mcp get bambuddy
```

进入交互界面后也可以使用 `/mcp` 查看工具。MCP 工具目录在会话启动时加载;修改
Server 或工具 allowlist 后需要开启新会话。

## STDIO 手动启动

```bash
cd /absolute/path/to/bambuddy-mcp
.venv/bin/bambuddy-mcp
```

进程没有普通输出并持续等待 stdin 是正常现象。stdio 的 stdout 只能承载 MCP
协议消息,诊断日志不能写入 stdout。

## 验证

```bash
.venv/bin/pytest -q
```

离线测试覆盖:

- Tool discovery、输入/输出 Schema 和 annotations;
- API Token 与 Agent 请求头;
- FastAPI 错误映射;
- JSON 和图像大小限制;
- access code、IP、序列号、RFID 和原始状态数据脱敏;
- 摄像头快照的 MCP Image 输出。
- Streamable HTTP 配置、安全校验和 Bearer Token 验证。

## 下一阶段

当前版本提供 stdio、Streamable HTTP、只读工具和受保护的两阶段开始打印。后续按设计文档推进:

1. 增加 `printer.wait_for_state`;
2. 实现 pause/resume 等可恢复控制;
3. 增加服务端持久化 idempotency key;
4. 增加 OAuth 或外部身份提供商集成;
5. 添加 Bambuddy Skill 和 Plugin。

TDQS

A4.1/5.0

Scored across 9 tools

Disambiguation4/5

Most tools target clearly distinct resources and actions, such as camera snapshot versus camera status or list printers versus diagnose printer. The only mild overlap is between get_printer_status and get_current_print, since both could reasonably be used to check ongoing print progress.

Naming Consistency5/5

Every tool follows the same bambuddy_<verb>_<noun> snake_case pattern with verbs like get, list, prepare, start, and diagnose. This makes the API surface highly predictable and easy for an agent to navigate.

Tool Count5/5

Nine tools is well within the ideal range and each tool serves a meaningful part of the printer monitoring and print-starting workflow. No tool feels redundant or unnecessary.

Completeness4/5

The core read-only monitoring, camera access, and safe print-start workflow are well covered, including preflight token handling. Minor lifecycle gaps exist, such as no cancel, pause, or print queue management tools, but the available surface supports the apparent primary use case.

Maintenance

ActivityMaintained
ResponsivenessSyncing