docs: MCP.md 校准 + spec 实测与终审偏离记录

- 工具表:scan_devices 返回形状 data.devices=[{name,address,rssi}];
  device_status 注明触发连接守候且刷新空闲计时(周期轮询阻止 idle 断开)
- 启动参数表新增 --allowed-hosts;Windows 部署段同步(含 421 说明)
- 连接行为节:重连覆盖面改为传输层异常全家
- spec 末尾加「实测与终审偏离记录」:5 码契约(DEVICE_DISCONNECTED 未 emit)、
  mac 解析顺序修正(启动 --mac > 自动扫描记住,工具面无 mac 参数)、
  异常面适配、熠管家 Windows 实测结论与 421 修复

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
chenweiandClaude committed 2026-07-30 23:56:01 +00:00
1 parent 4819715c4d
commit e8feb2d34a
2 files changed
+32 -5

No files matched your search

+9 -5
View File
@@ -39,6 +39,7 @@ PPCLOCK_MCP_TOKEN=<token> ppclock-mcp --transport http --host 0.0.0.0 --port 897
| `--mac` | 无 | 设备 MAC;缺省自动扫描 `NRF-` 前缀并记住实际地址 |
| `--connect-timeout` | `90.0` | 守候连接秒数(覆盖设备 30-60s 广播窗口) |
| `--idle-timeout` | `300.0` | 空闲断开秒数;`0` = 每次调用独立连接 |
| `--allowed-hosts` | 无 | HTTP Host 白名单(逗号分隔)。HTTP 模式绑非回环地址时**必须**把本机的局域网地址加进来(如 `192.168.61.35:8972,localhost:8972`),否则 LAN Host 请求被 DNS 重绑定防护拒绝(421);缺省仅 localhost 族 |
环境变量:`PPCLOCK_MCP_TOKEN` —— HTTP 模式 Bearer 鉴权令牌(仅 HTTP 使用;stdio 无鉴权,
信任本机进程)。
@@ -60,8 +61,8 @@ streamable HTTP 端点为 `http://<host>:8972/mcp`,请求头携带
| 工具 | 参数 | 说明 |
|---|---|---|
| `scan_devices` | `timeout: float = 5.0` | 扫描附近 NRF- 前缀墨水屏设备,返回 `[{name,address,rssi}]` |
| `device_status` | 无 | 查询连接状态/绑定 MAC/设备 ID/空闲秒数 |
| `scan_devices` | `timeout: float = 5.0` | 扫描附近 NRF- 前缀墨水屏设备;返回形状 `data.devices = [{name,address,rssi}]` |
| `device_status` | 无 | 查询连接状态/绑定 MAC/设备 ID/空闲秒数。会触发连接守候(最长 `--connect-timeout` 秒)并刷新空闲计时——周期轮询本工具会阻止 idle 自动断开 |
| `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` |
@@ -107,8 +108,8 @@ streamable HTTP 端点为 `http://<host>:8972/mcp`,请求头携带
设备回睡眠。`--idle-timeout 0` 退化为每次调用独立连接。
- **串行**:所有设备操作经一把锁串行执行(BLE 适配器独占),并发调用自动排队,不会
互相打断。
- **重连一次**:操作中连接丢失(TransportError)→ 断开重连并重试一次,再失败才向上
返回错误。
- **重连一次**:操作中连接丢失(传输层异常全家:SDK `TransportError`、bleak 裸抛
`BleakError`、平台 `OSError`/超时)→ 断开重连并重试一次,再失败才向上返回错误。
## Windows 部署(蓝牙所在机)
@@ -116,10 +117,13 @@ streamable HTTP 端点为 `http://<host>:8972/mcp`,请求头携带
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
.venv\Scripts\ppclock-mcp --transport http --host 0.0.0.0 --port 8972 `
--allowed-hosts "192.168.61.35:8972,localhost:8972" # 换成本机局域网地址
```
- 防火墙放行 **8972/tcp**,仅对局域网段开放(勿暴露公网;token 是唯一防线)。
- `--allowed-hosts` 必须包含本机的局域网地址(Host 头按 `<IP>:<port>` 匹配),
漏配时局域网请求被 mcp 的 DNS 重绑定防护拒绝(421)。
- 不动既有 **8971** bridge 与其他服务:8972 为独立端口、独立进程。
- `--mac` 建议显式指定设备地址,避免自动扫描误绑其他 `NRF-` 设备。
@@ -122,3 +122,26 @@ mac 解析顺序:工具参数 > 启动 `--mac` > 自动扫描首个 NRF-(并
- 多设备并发(单适配器串行已够;mac 参数可切换设备)
- MCP resources/prompts(本期只 tools)
- Windows 服务化、Linux 硬件实测(后续迭代)
## 实测与终审偏离记录(2026-07-30)
实现与终审后对原设计的偏离,逐条留痕:
- **错误码实为 5 码**:`DEVICE_DISCONNECTED` 未 emit——操作中途掉线被
DeviceManager 的"重连+重试一次"吸收,重试仍败按 `BLE_ERROR` 上报;工具面
始终只看到最终失败,无法区分"中途掉过线"。契约保留 5 码:
`INVALID_PARAM` / `DEVICE_NOT_FOUND` / `CONNECT_TIMEOUT` / `BLE_ERROR` /
`INTERNAL`。
- **mac 解析顺序修正**:实际为"启动 `--mac` > 自动扫描首个 `NRF-` 前缀并记住",
工具面无 mac 参数(原设计的"工具参数 > …"未实现;多设备切换靠重启服务器
换 `--mac`,归入 YAGNI 多设备并发)。
- **异常面适配真实硬件**:全部测试 fake 原来只抛英文 `transports.base.
TransportError`;真实 bleak 路径抛的是中文 `transports.local.TransportError`
(与 base 同名但互不继承)与**未包装**的 `BleakError`(如 `Not connected`)。
终审后 MCP 层捕获面扩为异常全家(两个 TransportError + BleakError + OSError
+ asyncio.TimeoutError),错误码按类型优先、消息(中英文)次之映射。
- **2026-07-30 熠管家 Windows 实测**:stdio 全链路通过(scan → connect →
set_time → upload_image 15000+15000 字节 → set_mode image0;远程无法目视
确认上屏)。HTTP 模式 LAN Host 被 mcp DNS 重绑定防护 421——已修:新增
`--allowed-hosts`(逗号分隔 Host 白名单,`TransportSecuritySettings`
实现,mcp 1.29.0 实测 API 与设计一致),Windows 部署文档同步更新。