docs+release: MCP.md 工具参考与部署指南;0.2.0

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
chenweiandClaude committed 2026-07-30 16:59:07 +00:00
1 parent 9506490ce2
commit de683fe9c2
7 files changed
+193 -11

No files matched your search

+138
View File
@@ -0,0 +1,138 @@
# ppclock-mcp · MCP 服务器参考(v0.2.0)
> 面向 agent 挂载与部署的工具级参考。SDK 签名见 `docs/sdk/API.md`,协议细节见 `docs/protocol.md`。
## 一句话
ppclock-mcp 是跑在**蓝牙物理所在机器**上的单层 MCP 服务器:13 个工具覆盖对时 / 模式 /
切换 / 传图 / 模板 / 倒计时 / 日历文字 / 休眠 / 刷屏 / raw 逃生舱,agent 经 stdio 或
streamable HTTP 直接驱动 4.2" 墨水屏设备。
## 安装
```bash
pip install -e ".[mcp]" # 追加依赖:mcp>=1.10,<2
```
要求:Python ≥ 3.10、本机蓝牙适配器(bleak)。服务器与被控设备在同一台蓝牙主机上;
不需要互联网。
## 启动
入口为 console script `ppclock-mcp`(`python -m ppclock.mcp_server` 不受支持)。
```bash
# stdio —— 本机 agent 直挂
ppclock-mcp --mac AA:BB:CC:DD:EE:FF
# streamable HTTP —— 局域网 agent 平台远程调用
PPCLOCK_MCP_TOKEN=<token> ppclock-mcp --transport http --host 0.0.0.0 --port 8972
```
启动参数:
| 参数 | 默认 | 说明 |
|---|---|---|
| `--transport` | `stdio` | `stdio` / `http` |
| `--host` | `127.0.0.1` | HTTP 绑定地址;绑非回环地址**必须**设 `PPCLOCK_MCP_TOKEN`,否则拒绝启动 |
| `--port` | `8972` | HTTP 端口 |
| `--mac` | 无 | 设备 MAC;缺省自动扫描 `NRF-` 前缀并记住实际地址 |
| `--connect-timeout` | `90.0` | 守候连接秒数(覆盖设备 30-60s 广播窗口) |
| `--idle-timeout` | `300.0` | 空闲断开秒数;`0` = 每次调用独立连接 |
环境变量:`PPCLOCK_MCP_TOKEN` —— HTTP 模式 Bearer 鉴权令牌(仅 HTTP 使用;stdio 无鉴权,
信任本机进程)。
## Agent 挂载示例
```bash
# Claude Code(stdio)
claude mcp add ppclock -- ppclock-mcp --mac AA:BB:CC:DD:EE:FF
```
streamable HTTP 端点为 `http://<host>:8972/mcp`,请求头携带
`Authorization: Bearer <PPCLOCK_MCP_TOKEN>`;token 不符返回 401。HTTP 为无状态模式
(`stateless_http`),无需会话保持。
## 13 工具参考
全部工具 async,返回统一契约(见下节)。参数与行为逐字对齐 `src/ppclock/mcp_tools.py`。
| 工具 | 参数 | 说明 |
|---|---|---|
| `scan_devices` | `timeout: float = 5.0` | 扫描附近 NRF- 前缀墨水屏设备,返回 `[{name,address,rssi}]` |
| `device_status` | 无 | 查询连接状态/绑定 MAC/设备 ID/空闲秒数 |
| `set_time` | `tz: float = 8.0` | 对时;tz 为时区偏移(默认 8=北京时间) |
| `set_mode` | `mode: str` | 切换显示模式:`clock1-3`/`calendar1-3`/`image0-3`/`tricolor`/`mono` |
| `toggle` | `name: str` | 单字节切换:`invert`/`font`/`rotate180`/`hour_format`/`clock_color` |
| `upload_image` | `source: str, slot: int = 0, algo: str = "atkinson", mono: bool = False, threshold/diffusion/brightness/contrast/saturation/rotate: float\|None = None` | 传图到指定槽位。`source` = 服务器路径或 base64(可带 data URI 前缀);`algo` ∈ `none/floydsteinberg/atkinson/bayer/stucki/jarvis`;6 个可选 adjust 参数:`threshold`/`diffusion`/`brightness`/`contrast`/`saturation`/`rotate`(仅显式传入时生效) |
| `render_template` | `name: str, payload: dict\|None = None, slot: int = 0, algo: str = "atkinson"` | 本地渲染模板并上传:`schedule`/`businesscard`/`memo`/`course`/`qrcode`/`custom` |
| `countdown` | `date: str, mode: str = "clock", prefix: str\|None = None` | 倒计时;`date` 为 ISO `YYYY-MM-DD`;`mode` = `clock`/`calendar` |
| `countdown_off` | 无 | 关闭倒计时 |
| `calendar_text` | `text: str` | 设置日历中文文字并切到日历模式一 |
| `set_sleep` | `on: bool, start_h: int, end_h: int` | 设置休眠时段(0-23 时) |
| `clear_screen` | 无 | 刷屏(EPD 清屏) |
| `raw_send` | `data_hex: str, channel: str = "alt"` | 逃生舱:直发十六进制字节串;`channel` = `rxtx`/`epd`/`alt` |
`device_status` 返回字段:`connected` / `mac` / `device_id`(尽力而为,失败省略)/
`idle_seconds` / `connect_count` / `connect_timeout` / `idle_timeout`。
## 输出契约与错误码
与 CLI `--json` 同构的统一契约:
```json
成功 {"ok": true, "tool": "<name>", "data": {...}}
失败 {"ok": false, "tool": "<name>", "error": {"code", "message", "hint"?}}
```
错误码(5 种):
| code | 触发 | hint |
|---|---|---|
| `CONNECT_TIMEOUT` | 守候窗口内未连上设备 | 设备长睡眠、广播窗口 30-60s;调大 `--connect-timeout` 或稍后重试 |
| `DEVICE_NOT_FOUND` | 扫描未发现设备 | 未发现 NRF- 前缀设备;确认设备在位且未处于深睡 |
| `BLE_ERROR` | 其他传输层错误 | 无 hint |
| `INVALID_PARAM` | 参数校验失败(非法 base64/非图片/非法日期/非法 hex 等) | 无 hint,message 给出具体原因 |
| `INTERNAL` | 工具层兜底未分类异常 | 无 hint,message 为 `类型: 详情` |
`hint` 仅对 `CONNECT_TIMEOUT` / `DEVICE_NOT_FOUND` 出现,语义是给 agent 的可执行恢复建议
(调参重试 / 检查设备),不是给人看的错误描述。
## 连接行为(方案 C:按需连接 + 空闲保持)
- **守候窗口**:首次操作发起连接,守候 `--connect-timeout` 秒(默认 90s,覆盖设备
30-60s 广播窗口);设备在深睡中也能等到其广播。
- **空闲超时**:操作完成后保持连接;空闲 `--idle-timeout` 秒(默认 300s)自动断开让
设备回睡眠。`--idle-timeout 0` 退化为每次调用独立连接。
- **串行**:所有设备操作经一把锁串行执行(BLE 适配器独占),并发调用自动排队,不会
互相打断。
- **重连一次**:操作中连接丢失(TransportError)→ 断开重连并重试一次,再失败才向上
返回错误。
## Windows 部署(蓝牙所在机)
```powershell
python -m venv .venv
.venv\Scripts\pip install -e ".[mcp]"
setx PPCLOCK_MCP_TOKEN "<token>" # 或按服务方式注入环境变量
.venv\Scripts\ppclock-mcp --transport http --host 0.0.0.0 --port 8972
```
- 防火墙放行 **8972/tcp**,仅对局域网段开放(勿暴露公网;token 是唯一防线)。
- 不动既有 **8971** bridge 与其他服务:8972 为独立端口、独立进程。
- `--mac` 建议显式指定设备地址,避免自动扫描误绑其他 `NRF-` 设备。
## 不暴露的能力
以下 SDK 能力**有意不**注册为 MCP 工具:
| 能力 | 原因 |
|---|---|
| OTA 固件升级(`ota`) | 高危写闪存,agent 误调用可砖机;只走 CLI 显式 `--yes` 授权路径 |
| 激活(`activate`/`activate_auto`) | 一次性出厂级操作,日常 agent 场景不需要;保留在 SDK/CLI |
| LUT 校准(`lut`) | 面板厂商级调试参数,误刷影响显示质量 |
| WiFi 配置(`wifi`) | 本固件为 no-op(固件证据),暴露只会误导 agent |
| 轮播(`rotation`) | 本固件为 no-op(固件证据),同上 |
需要这些能力时按 `docs/sdk/API.md` 走 SDK/CLI,不经 MCP 面。