内容
# 月球漫步器 MCP



一个 [MCP](https://modelcontextprotocol.io) 服务器,允许 AI 客户端(Claude Desktop / Claude Code)通过 [Moonraker API](https://moonraker.readthedocs.io/en/latest/external_api/introduction/) 查询和控制 Klipper 3D 打印机。
它作为一个小型 HTTP 守护进程运行 - 设计用于与 Moonraker 放在一起 - 并将打印机状态、温度、文件、打印作业控制和 G-code/宏执行作为 MCP 工具公开。
> ## ⚠️ 安全与防护 - 请先阅读
>
> 该服务器允许 AI 客户端 **物理控制 3D 打印机** - 可达 250 °C 的加热器、移动的工具头和无人值守的打印作业。请相应地处理:
>
> - **仅在受信任的局域网中运行。永远不要将 8790 端口暴露在互联网上。** 它默认绑定 `0.0.0.0`。请将其放在防火墙/VPN(例如 Tailscale)后面,而不是端口转发。
> - **设置 `MCP_AUTH_TOKEN`。** 空值表示端点 **未经身份验证** - 任何可以访问它的人都可以获得完整的打印机控制权限。
> - **监督打印作业。** 确认门控(如下所述)减少了意外的破坏性调用,但它不能替代人类监控热的、移动的硬件。请将紧急停止按钮放在可及范围内。
## 确认门控
提供完全控制,但 **危险操作在未再次调用 `confirm=true` 时拒绝运行**。当缺少确认时,工具不会执行任何操作,并返回一个描述将发生的操作的消息,AI 将其显示给您作为是/否提示。受控操作:
- `emergency_stop`
- `cancel_print`
- `pause_print`
- `run_gcode` / `run_macro` - **仅当** 命令驱动加热器(`M104/M109/M140/M190/M141/M191/SET_HEATER_TEMPERATURE/TEMPERATURE_WAIT`)
- `start_print`, `resume_print`
- `firmware_restart`, `restart_host`, `delete_file`
非加热器 `run_gcode`/`run_macro` 是唯一允许在无需确认的情况下更改状态的操作。
## 需求
- **Python 3.10+** (硬性要求 - `mcp` SDK 和几个依赖项拒绝在旧版本上安装)
- 可访问的 **Moonraker** 实例(Klipper 打印机),本地或远程
- 对于部署路径:带有 systemd 的 **Linux 主机** (例如 Raspberry Pi OS)- 安装脚本设置了 systemd 服务。服务器本身是纯 Python 代码,也可以在 Windows/macOS 上运行用于本地开发。
> ### ⚠️ 在打印机主机上检查 Python 版本
>
> 运行 `python3 --version` **首先**。许多 Klipper/Moonraker 主机运行较旧的操作系统镜像,附带 Python **3.9 或更早** - 特别是 **Debian Bullseye** 和旧的 **Raspberry Pi OS** 镜像,以及较旧的 **Armbian** 构建(其中一些版本为 3.8)。`bullseye-backports` 不提供更新的解释器,因此 `apt` 无法为您提供帮助。如果您的 `python3` 版本低于 3.10,`bash deploy/install.sh` 将在依赖项解析期间失败 - **在** 触及您的打印机配置 **之前**。
>
> 修复方法,从最简单的开始:
> - 使用基于 **Bookworm** 的镜像(附带 Python 3.11)。
> - 在 **Docker** 中运行服务器,基于 `python:3.11-slim` - 完全跳过主机解释器。
> - 通过 **pyenv** 安装 3.10+,并将服务虚拟环境指向它(systemd 单元已经调用显式 `venv/bin/python`)。
## 配置
复制 `.env.example` 到 `.env`(或在 systemd 单元中设置环境变量):
| 变量 | 默认值 | 用途 |
| --- | --- | --- |
| `PRINTERS_FILE` | _(自动)_ | 多打印机 TOML/JSON 文件的路径(见下文) |
| `MOONRAKER_URL` | `http://localhost:7125` | 单打印机 URL(仅在没有打印机文件时使用) |
| `MOONRAKER_API_KEY` | _(空白)_ | `X-Api-Key`; 空白表示受信任的局域网客户端 |
| `MCP_HOST` | `0.0.0.0` | 绑定地址 |
| `MCP_PORT` | `8790` | 绑定端口 |
| `MCP_AUTH_TOKEN` | _(空白)_ | 客户端必须发送的 Bearer Token。**空白 = 未经身份验证** |
| `REQUEST_TIMEOUT` | `10` | 对 Moonraker 的每个请求超时(秒) |
### 一个或多个打印机
单个 MCP 实例可以支持 **多个** 打印机(每个打印机都是一个远程 Moonraker)。在 TOML 或 JSON 文件中定义它们 - 复制 `printers.example.toml` 到 `printers.toml`(在工作目录中自动检测)或设置 `PRINTERS_FILE`。`printers.toml`/`printers.json` 被 gitignore,因为它们包含您的 URL 和 API 密钥;只有 `.example` 模板被跟踪。
```toml
[[printers]]
name = "voron"
url = "http://voron.local:7125"
primary = true
[[printers]]
name = "ender"
url = "http://ender.local:7125"
```
然后,每个工具都接受一个可选的 `printer` 参数(配置的打印机名称;省略则默认为主要打印机)。`list_printers` 会枚举它们。当没有找到打印机文件时,服务器会回落到单个打印机的 `MOONRAKER_URL`(命名为 `default`)- 因此现有的单打印机设置保持不变。
## 在本地运行(开发)
```bash
python -m venv venv && ./venv/bin/pip install -e ".[dev]" # Windows: venv\Scripts\pip
cp .env.example .env # 编辑 MOONRAKER_URL
python -m moonraker_mcp
```
MCP 端点在 `http://<host>:<port>/mcp` 处提供服务(可流式传输的 HTTP - 当前的 MCP HTTP 传输;这是 Claude 的“HTTP/SSE”连接器所期望的)。
### 使用 MCP 检查器进行交互式测试
```bash
mcp dev src/moonraker_mcp/server.py # 或使用检查器针对正在运行的 URL
```
## 在 Raspberry Pi 上部署
> **开始前:** 在 Pi 上运行 `python3 --version` 并确认它是 3.10+(参见上面的 [Python 版本警告](#requirements))- 否则安装将失败。
首次安装,在 Pi 上运行:
```bash
git clone https://github.com/<your-username>/moonraker-mcp.git ~/moonraker-mcp && cd ~/moonraker-mcp
bash deploy/install.sh # 创建虚拟环境,安装,设置 systemd
sudo nano /etc/moonraker-mcp.env # 设置 MOONRAKER_URL + MCP_AUTH_TOKEN
sudo systemctl restart moonraker-mcp
```
`install.sh` 可以安全地重新运行:它会重新安装包并重启单元,并且永远不会覆盖现有的 `/etc/moonraker-mcp.env`。要更新现有的安装,请拉取最新版本并重新运行:
```bash
cd ~/moonraker-mcp && git pull && bash deploy/install.sh
```
## 从 Claude 连接
添加一个指向 `http://<pi-host>:8790/mcp` 的 HTTP MCP 服务器,并带有 `Authorization: Bearer <MCP_AUTH_TOKEN>` 头。示例(`claude_desktop_config.json` / `.mcp.json`):
```json
{
"mcpServers": {
"moonraker": {
"url": "http://printer.local:8790/mcp",
"headers": { "Authorization": "Bearer YOUR_TOKEN" }
}
}
}
```
## 工具
所有工具都接受一个可选的 `printer` 参数(配置的打印机名称;省略则默认为主要打印机)。
发现:`list_printers`。
读取:`get_printer_status`, `get_print_status`, `get_temperatures`, `list_printer_objects`, `get_printer_info`, `get_server_info`, `query_endstops`, `get_temperature_history`, `get_recent_gcode_responses`, `get_gcode_help`.
文件:`list_gcode_files`, `list_files`, `get_file_metadata`, `get_file`, `delete_file`*.
`get_file` 读取原始文件内容(G-code, 配置等)并带有可选的字节范围。它以 `max_bytes` 为上限(默认为 32 KB),当上限截断响应时标记 `truncated` - 传 `start_byte`(来自 `get_file_metadata` 的 `gcode_start_byte`)以跳过切片器头部并采样打印主体。
控制:`start_print`*,`pause_print`*,`resume_print`*,`cancel_print`*,`run_gcode`*,`run_macro`*,`emergency_stop`*,`firmware_restart`*,`restart_host`*.
服务器配置:`get_server_config`.
历史记录:`get_history`, `get_history_totals`, `get_history_job`, `reset_history_totals`*,`delete_history_job`*.
网络摄像头:`list_webcams`, `get_webcam`, `test_webcam`, `set_webcam`*,`delete_webcam`*.
传感器:`list_sensors`, `get_sensor_info`, `get_sensor_measurements`.
Spoolman:`get_spoolman_status`, `get_active_spool`, `set_active_spool`, `spoolman_proxy`*(仅针对非 GET 方法进行门控)。
(\* = 确认门控。`run_gcode`/`run_macro` 仅当存在加热器命令时;`spoolman_proxy` 仅针对非 GET 方法。)
## 测试
```bash
./venv/bin/pytest
```
## 许可证
[MIT](LICENSE) © 月球漫步器 MCP 贡献者