内容
# 总线MCP
一个MCP服务器,为AI代理(Claude Desktop、Claude Code或任何MCP兼容客户端)提供直接访问树莓派外围总线的权限:
- **CAN / CAN-FD** — SocketCAN(PiCAN、Waveshare 2-CH CAN HAT、CM5上的板载CAN)
- **RS485 / UART** — pyserial (`/dev/ttyUSB*`, `/dev/ttyAMA*`, `/dev/ttyS*`)
- **I2C** — smbus2 (`/dev/i2c-1`, `/dev/i2c-3`)
- **SPI** — spidev (`/dev/spidev0.0`, 等)
- **GPIO** — lgpio(Pi 4 / Pi 5 / CM4 / CM5)
代理获得了一套小型、精选的工具集 — `bus_list`、`can_send`、`i2c_read`、`gpio_write`等 — 以及每个总线的`*_configure`工具,以便在会话期间重新调整波特率/波特率/SPI模式。指向Pi并使其与传感器通信、转储CAN流量或摆动引脚,而无需先编写Python脚本。

## 在Pi上快速安装
```bash
git clone https://github.com/Pan-Robotics/bus-mcp.git
cd bus-mcp
./packaging/install.sh --allow-write
```
就这样。安装程序:
- 创建`~/.local/share/bus-mcp/.venv`,并使用`--system-site-packages`,以便重用apt包装的`lgpio` / `pyserial` / `smbus2` / `spidev`(无需SWIG重建)
- 安装`mcp` + `python-can` + `bus-mcp`本身
- 将您添加到`spi` / `i2c` / `gpio` / `dialout`组
- 安装`/etc/systemd/system/bus-mcp.service`并启用它
- 打印MCP端点URL +您的主机的`claude mcp add`行
它**不**会触及`/boot/firmware/config.txt`(CAN HAT覆盖因HAT变体而异),选择CAN波特率或打开防火墙端口。
重新运行是幂等的。要删除所有内容:`./packaging/install.sh --uninstall`。
## 手动安装(PyPI,无systemd)
在Pi上:
```bash
pip install "bus-mcp[pi-all]"
```
在开发笔记本电脑(无硬件)上 — 用于编辑 + 测试:
```bash
pip install bus-mcp
```
总线库(`python-can`、`pyserial`、`smbus2`、`spidev`、`lgpio`)延迟加载。缺少的库仅在您调用需要它们的工具时出错。
## 运行
```bash
bus-mcp list # 显示已发现的总线
bus-mcp serve # stdio(Claude Desktop / Code)
bus-mcp serve --allow-write # 每次总线写入
bus-mcp serve --allow-write=can,serial # 仅在CAN + 串行写入
# HTTP / streamable-http传输(默认仅限localhost)
bus-mcp serve --transport http
bus-mcp serve --transport http --port 7820 --allow-write
bus-mcp serve --transport http --host 0.0.0.0 --port 7820 # LAN可达
```
HTTP端点位于`http://<host>:<port>/mcp`,并使用MCP streamable-HTTP协议(POST JSON-RPC,响应为单个SSE消息)。默认绑定为`127.0.0.1`,因此服务器在您选择`--host 0.0.0.0`(和SSH隧道/防火墙规则来限制访问)之前,对Pi外部是不可见的。
## 连接到Claude Desktop(stdio)
编辑`~/.config/Claude/claude_desktop_config.json`:
```json
{
"mcpServers": {
"bus-mcp": {
"command": "bus-mcp",
"args": ["serve", "--allow-write"]
}
}
}
```
## 连接到Claude Code
stdio(同一Pi上的Claude Code):
```bash
claude mcp add bus-mcp -- bus-mcp serve --allow-write
```
HTTP(Pi在`pi.local:7820`上可达,或替换您的主机名/IP):
```bash
claude mcp add --transport http bus-mcp http://pi.local:7820/mcp
```
安装程序在运行结束时打印确切的URL。
## 代理获得的工具
| 工具 | 目的 |
| ------------------- | ------------------------------------------------------ |
| `bus_list` | 枚举已发现的总线 |
| `bus_status` | 检查描述符 + 存储的配置(无驱动程序打开) |
| `bus_close` | 释放代理 earlier打开的总线 |
| `write_permissions` | 显示已启用写入的总线种类 |
| `can_configure` | 设置波特率 / fd / data_bitrate / restart_ms |
| `can_send` | 传输CAN / CAN-FD帧 |
| `can_receive` | 排空帧,带有可选内核过滤 |
| `serial_configure` | 设置波特率 / 字节大小 / 奇偶校验 / 停止位 / 流控 |
| `serial_send` | 向UART / RS485端口写入字节 |
| `serial_receive` | 从UART / RS485端口读取字节 |
| `i2c_read` | 从设备寄存器读取 |
| `i2c_write` | 向设备寄存器写入 |
| `i2c_scan` | `i2cdetect`等效地址探测 |
| `spi_configure` | 设置max_speed_hz / mode / bits_per_word / lsb_first |
| `spi_xfer` | 全双工传输(可选每次调用速度) |
| `gpio_configure` | 设置方向 / 拉伸 / 活动低 / 去抖 |
| `gpio_read` | 读取引脚 |
| `gpio_write` | 驱动引脚 |
`*_configure`工具将所有字段作为可选kwargs — 只传递您要更改的内容。总线立即关闭,因此下一个调用会用新配置重新打开它。阻塞接收工具(`can_receive`、`serial_receive`、`i2c_scan`)通过`asyncio.to_thread`在工作线程上运行,因此单个客户端可以在并行触发其他工具调用的同时保持长时间接收打开。
## 安全
默认情况下,**所有总线均为只读**。写入工具会干净地拒绝,并附带一条消息,指明正确的`--allow-write`标志。拒绝作为MCP工具错误返回,以便代理可以显示状态而不是崩溃。
协议级别上没有写入门控之后的检查:如果您启用写入,代理传输破坏性的CAN帧,您的ECU会看到它。在测试台设置上使用,而不是在没有硬件杀死开关的实时车辆上。
## 在Pi上验证 — Waveshare 2-CH CAN HAT环回
[Waveshare 2-CH CAN HAT][wsh]为您提供两个MCP2515通道,暴露为`can0` + `can1`。当两个通道相互连接(CAN_H ↔ CAN_H,CAN_L ↔ CAN_L,**加上两个侧面上启用板载120 Ω终端跳线**)时,一个通道上发送的帧会落在另一个通道上 — 一个完美的端到端测试。
[wsh]: https://www.waveshare.com/2-ch-can-hat.htm
```bash
# 1. 启用SPI + 覆盖层(一次性)。
# 这些值适用于原始的2-CH CAN HAT(16 MHz晶体,
# GPIO 23 + 25上的IRQ)。HAT +变体使用不同的引脚 —
# 在粘贴前检查您的HAT。
sudo raspi-config nonint do_spi 0
sudo tee -a /boot/firmware/config.txt <<'EOF'
dtoverlay=mcp2515-can0,oscillator=16000000,interrupt=23
dtoverlay=mcp2515-can1,oscillator=16000000,interrupt=25
EOF
sudo reboot
# 2. 重新启动后 — 启动两个接口。
sudo ip link set can0 up type can bitrate 500000
sudo ip link set can1 up type can bitrate 500000
# 3. 安装bus-mcp并启动它。
./packaging/install.sh --allow-write # 或:bus-mcp serve --transport http --allow-write &
# 4. 从代理(或直接使用curl):练习环回:
# - 在can0上:can_send {arbitration_id=0x123, data_hex="deadbeef"}
# - 在can1上:can_receive {timeout_s=1, count=1}
# 预期:一个帧,仲裁ID = 0x123,数据 = "deadbeef"
```
原始卷烟测试(初始化MCP会话)- 替换您的Pi的主机名/IP为`<HOST>`:
```bash
curl -i -X POST -H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
--data '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"0.0.1"}}}' \
http://<HOST>:7820/mcp
```
如果控制器稳定在`ERROR-PASSIVE`而不是`ERROR-ACTIVE`(`ip -details link show can0`),则板载终端跳线可能未启用。启用它们或将波特率降低到总线可以承受的值(`sudo ip link set can0 down; sudo ip link set can0 type can bitrate 250000; sudo ip link set can0 up`)。
## 架构
参见[`docs/architecture.png`](docs/architecture.png)以获取完整的分层视图,或在编辑后重新渲染:
```bash
python docs/render_arch.py # 写入docs/architecture.png
```
渲染脚本(`docs/render_arch.py`)使用纯PIL - 无`dot` / `mmdc` / 浏览器引擎 - 并根据最高的框自动调整每个层带的宽度,因此添加工具或驱动程序不需要手动布局调整。
## 日志 + 服务控制(仅限systemd安装)
```bash
sudo systemctl status bus-mcp # 它是否启动?
sudo systemctl restart bus-mcp # 重启它
sudo journalctl -u bus-mcp -f # 尾部日志
sudo journalctl -u bus-mcp --since=-1h # 过去一小时
```
## 路线图
- mDNS在LAN上宣传,以便漫游代理可以找到Pi
- HTTP端点身份验证(共享密钥标头)
- `can_receive`上过滤表达式超出单个ID +掩码
- PyPI发布(今天:从源代码安装)
## 许可证
MIT - 请参阅[LICENSE](./LICENSE)。