Files
auto_control/doc/MCP_DESIGN.md
T

14 KiB
Raw Blame History

MCP 手机控制(Mobile Control MCP Server)设计文档

分支:dev:mcp | 状态:设计稿 | 日期:2026-09-04

1. 背景与目标

平台(auto_control,生产 220:18050)已具备完整的手机远程控制与自动化能力:设备池管理、u2 控制(tap/swipe/key/输入/剪贴板)、minicap 看屏(截图/流)、uiautodev 元素树、RapidOCR、任务调度与动作编辑器。

本设计的目标:新增一个 MCP Server,把平台能力以 MCP 协议暴露给多模态 AI(Claude 等),使 AI 能像人一样"看到手机屏幕 → 理解 → 操作 → 再看到"地闭环控制手机。

核心判断:平台能力全部已有,MCP Server 是薄封装层——主要工作在:工具规格设计、多模态图像链路、认证与安全、部署。

2. 术语

术语 说明
MCP Model Context Protocol,模型上下文协议(客户端-服务器,工具调用)
Tools MCP 暴露的可调用能力(本设计按 L1/L2/L3 分层)
serial 设备标识,如 192.168.20.66:5555(设备池唯一主键)
平台 指 auto_control web 服务(18050)及其 core 层能力
宿主 MCP Server 运行进程/容器

3. 总体架构

┌──────────────┐   MCP (Streamable HTTP / stdio)   ┌──────────────────┐
│  多模态 AI    │ ────────────────────────────────▶ │   MCP Server     │
│ Claude Desktop│   tools + image content block    │  (220 独立进程) │
│ Claude Code  │ ◀──────────────────────────────── │  mcp/ 包         │
└──────────────┘   截图图像 / JSON 结果             └────────┬─────────┘
                                                            │ 内部调用
                                                            ▼
                                                 ┌──────────────────┐
                                                 │ auto_control     │
                                                 │ 18050 REST API   │
                                                 │ (登录会话 token)│
                                                 ├──────────────────┤
                                                 │ core 层能力:     │
                                                 │ u2 / minicap /   │
                                                 │ uiautodev / OCR /│
                                                 │ 任务调度 / 设备池 │
                                                 └──────────────────┘
  • 图像方向:MCP 协议支持 image content block(base64),截图以此返回,多模态模型原生可读——这是"AI 看到手机"的关键链路。
  • 控制方向:AI 返回结构化工具调用(tap/swipe/type…),MCP Server 转发平台执行。
  • 循环:截图 → 模型视觉推理 → 工具调用 → 平台执行 → 截图验证。

4. 平台现有能力复用清单

平台能力 现有入口 MCP 复用方式
设备列表/状态 GET /api/status、/api/devices/pool MCP server 内部 HTTP 调用(带会话)
截图 GET /api/screen/thumb?serial=(单帧 JPEG) 直接转发为 image block(亦可直连 core u2 screenshot)
看屏流 /api/screen/stream(MJPEG) M0-M2 不需要;M3 可选(视频理解场景)
点击 POST /api/screen/tap {serial,x,y} 封装 tool tap
滑动 POST /api/screen/swipe 封装 swipe
按键 POST /api/screen/key 封装 press_key
输入文字 ClipInject 通道(core.clipboard_helper)+ u2 input 封装 type_text
剪贴板 POST /api/tools/clipboard/set(ClipInject 通道) 封装 set_clipboard
元素树 GET /api/uiauto/...(uiautodev) 封装 get_ui_tree
OCR core.ocr(RapidOCR) 封装 ocr_screen
打开 App u2 app_start(经任务层/直连) 封装 open_app(走 core device 直连)
设备在线状态/亮熄屏 /api/device/screen_all、dumpsys 封装 screen_state/wake

决策:MCP Server 优先走 HTTP API(薄封装,认证简单、与平台解耦、平台安全逻辑全复用)。对延迟敏感且 HTTP 无入口的能力(u2 直连截图/输入),经平台 core 模块进程内调用或新增少量只读端点,不绕过平台安全层。

5. MCP Server 设计

5.1 技术栈

  • 语言/运行时:Python 3.11(与平台一致)
  • 框架:FastMCP(fastmcp,官方 SDK 之上,装饰器式 tools,自带 Streamable HTTP/stdio 双传输)
  • 依赖:fastmcp、httpx、Pillow(图像处理)、mcp[cli]
  • 日志:logging → 平台同款格式(时间/级别/模块)

5.2 进程与容器

  • 独立容器 mcp-server(220 docker-compose 追加),image python:3.11-slim
  • 挂载:无数据挂载(无状态,配置走环境变量);网络 host 或独立端口(候选:8033,避免与 18050/18051 冲突)
  • 独立于 auto_control 重启,互不阻塞;MCP Server 崩溃不影响平台,平台不可用时 MCP tools 返回明确错误

5.3 配置(环境变量)

变量 默认 说明
MCP_PLATFORM_URL http://127.0.0.1:18050 平台地址
MCP_PLATFORM_USER / MCP_PLATFORM_PASS 空 平台登录账号(admin)
MCP_ALLOW_WRITE 0 写操作总开关(0=只读感知,1=可操作)
MCP_ALLOWED_SERIALS 空=全部 设备白名单(逗号分隔;为空时自动=设备池内设备)
MCP_HTTP_PORT 8033 HTTP 传输端口
MCP_SCREENSHOT_WIDTH 540 截图宽度(等比缩放,控图像 token 成本)
MCP_JPEG_QUALITY 70 截图 JPEG 质量
MCP_AUDIT_FILE /var/log/mcp/audit.log 审计日志路径

6. Tools 规格

命名空间 de_(device)前缀避免与常见工具冲突。全部工具对未配置白名单/离线设备返回明确错误,不做静默跳过。

L1 感知层

de_list_devices

  • 描述:列出可控制设备及其状态(在线/任务/型号/前台 App)
  • 返回:[{serial, model, online, task_job, worker_status, foreground_app, screen_state}]
  • 错误:平台不可达 → platform_unavailable

de_screenshot(serial: str) -> image

  • 描述:截取设备当前屏幕(JPEG),返回 image content block;同时返回 width/height/serial 元信息
  • 实现:平台 /api/screen/thumb(X-Screen-State 头复用判断亮熄屏);失败(离线/超时)→ 明确错误
  • 图像规格:宽 ≤ MCP_SCREENSHOT_WIDTH(默认 540),质量 MCP_JPEG_QUALITY;需保证图像方向正确(设备可能横竖屏,含 EXIF 或由调用方按截图尺寸推断)
  • 限制:截图频率 ≥ 1s/次(防 AI 疯狂截图),可配置

de_ui_tree(serial: str) -> str

  • 描述:获取当前界面元素树(扁平 JSON:resource-id/text/content-desc/class/bounds),供定位
  • 返回:文本 JSON(大树截断至 MCP_UI_TREE_MAX 字符,默认 20000,防 context 爆炸)
  • 空界面/无元素 → 明确错误

de_ocr(serial: str) -> str

  • 描述:OCR 识别当前屏幕文字,返回 [{text, score, box}]
  • 场景:图片/画布/WebView 渲染文字(UI 树里没有的)

de_screen_state(serial: str) -> str

  • 描述:亮屏/熄屏/未知

L2 操作层(受 MCP_ALLOW_WRITE=1 门控)

de_tap(serial, x: int, y: int)

  • 坐标:设备原生分辨率像素(与截图 1:1 换算——调用方用截图尺寸按比例换算,server 不做猜测)

de_swipe(serial, x1,y1,x2,y2, duration: float=0.2)

de_press_key(serial, key: str)

  • key ∈ back/home/recent/menu/power/enter/delete…

de_type_text(serial, text: str, clear_first: bool=True)

  • 实现:优先 ClipInject 通道(core.clipboard_helper.inject_clipboard 语义:写入剪贴板 + paste 到焦点输入框),失败回退 u2 input
  • 中文/emoji 全支持(ClipInject 实测通过)

de_set_clipboard(serial, text: str)

  • 写入设备剪贴板(ClipInject am start 通道),读回验证

de_open_app(serial, package: str)

  • 打开指定 App(u2 app_start);package 需在已知清单或完全限定名

de_wake(serial) / de_sleep(serial)

L3 语义层(M2 里程碑)

de_find_and_tap(serial, target: str, by: "text"|"id"|"ocr"|"desc"=...)

  • UI 树/OCR 定位含 target 的元素 → 自动点击其中心;多命中返回候选列表让 AI 选择
  • 复用平台元素选择器策略(属性唯一/重复序号消歧)

de_wait_until(serial, condition: str, timeout: int=15)

  • 轮询 OCR/UI 树直到出现条件文本(或消失),返回命中的坐标/文本

de_get_task_state(serial)(若二期接任务系统)

  • 设备当前任务状态;可选 de_run_task(task_id) 需单独授权

工具返回约定

  • 全部工具返回结构化 JSON:{ok: true, data: ...} 或 {ok: false, error: {code, message}}
  • 错误码:platform_unavailable / device_offline / device_not_allowed / invalid_param / write_disabled / busy(设备被任务占用)
  • image 返回:{ok:true, image: <content block>, width, height}

7. 图像链路细节

  1. 平台截图(/api/screen/thumb)→ JPEG 字节
  2. MCP Server 校验尺寸 → 等比缩放到 MCP_SCREENSHOT_WIDTH(用 Pillow,不重压缩已够质量则跳过)
  3. 组装 MCP image content block({"type":"image","data":<base64>,"mimeType":"image/jpeg"})
  4. 客户端(Claude)原生把 image 传入视觉上下文

性能预算:540px JPEG ~40-80KB/张;模型一次多步操作 5-15 张 ≈ 1MB 以内,可接受。

8. 认证与安全

  1. 平台会话:MCP Server 启动时用 MCP_PLATFORM_USER/PASS 登录平台拿会话(Cookie),会话失效自动重登;不向客户端暴露平台凭据
  2. 写操作门控:MCP_ALLOW_WRITE=0(默认)时 L2/L3 操作全部拒绝(write_disabled)——先部署只读,验证感知链路后再开写
  3. 设备白名单:MCP_ALLOWED_SERIALS 指定;为空时自动限制为设备池 enabled 设备(平台口径)
  4. 占用互斥:操作前查设备 worker_status——running/connecting 中拒绝操作(busy),避免 MCP 与任务打架
  5. 审计:每次调用(含只读)写审计日志:ts|tool|serial|args摘要|result;落盘 MCP_AUDIT_FILE
  6. 传输安全:内网部署(host 网络 8033)默认无 TLS;若外网暴露需前置 TLS/网络隔离(平台红线:设备控制接口不进公网)
  7. 无状态:MCP Server 不存设备数据,全量透传平台

9. 部署(220 docker-compose 追加)

  mcp-server:
    container_name: mcp-server
    image: dockerproxy.net/library/python:3.11-slim
    restart: unless-stopped
    working_dir: /app
    volumes:
      - "./mcp_server:/app"
    command: sh -c "pip install --no-cache-dir -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt && python -m mcp_server"
    environment:
      - MCP_PLATFORM_URL=http://127.0.0.1:18050
      - MCP_PLATFORM_USER=admin
      - MCP_PLATFORM_PASS=${MCP_PLATFORM_PASS}   # .env 提供
      - MCP_ALLOW_WRITE=1
      - MCP_ALLOWED_SERIALS=
    network_mode: host

客户端接入(Claude Code / Desktop):

// .mcp.json / claude_desktop_config.json
{ "mcpServers": { "mobile": {
    "url": "http://192.168.20.220:8033/mcp",
    "transport": "streamable-http"
}}}

10. 里程碑与验收

里程碑 内容 验收标准
M0 Server 骨架 + de_list_devices + de_screenshot + de_tap/de_swipe(HTTP 传输、登录会话、审计骨架) Claude Code 连上后:能列设备、截图(AI 能描述屏幕内容)、点击指定坐标生效
M1 L1 完备(ui_tree/ocr/screen_state)+ L2 全量(key/type/clipboard/open_app/wake) AI 完成「打开抖音搜索『奚学东』」多步操作
M2 L3 语义层(find_and_tap/wait_until)+ 图像尺寸/性能调优 AI 用自然语言指令(含中文输入)完成跨 3 步以上操作且自适应页面变化
M3 生产化:安全加固复核、审计看板、部署脚本、接入文档、任务系统互斥回归 日常稳定使用 1 周无异常

11. 风险与开放问题

  1. AI 误操作:模型点击错位/误触关键按钮(如删除)——缓解:L3 定位优先于裸坐标、写门控先行、审计可追溯;不做二次确认(破坏自动化体验),靠白名单+占用互斥兜底
  2. 截图成本:长会话多截图 → token/延迟成本——缓解:尺寸/质量可调、截图上限、de_ui_tree 作为低成本替代(文本树比图像便宜)
  3. 横竖屏/分辨率异构:设备多样 → 坐标换算依赖截图 1:1;de_find_and_tap(语义层)不受分辨率影响
  4. 图像 content block 兼容性:Claude 系原生支持;其他多模态客户端需验证(M0 用 Claude Code 验证)
  5. 是否接任务系统:二期决策——de_run_task 语义与"单设备操作"不同(任务面向多设备调度),倾向二期用独立命名空间
  6. clipboard/input 通道差异:个别 MIUI 需授权 ClipInject——M0 阶段在受控设备集验证,必要时 fallback 链已在 core 层

12. 附录:平台 API 映射(MCP → 平台)

MCP tool 平台调用
de_screenshot GET /api/screen/thumb?serial=
de_tap / de_swipe / de_press_key POST /api/screen/tap
de_type_text / de_set_clipboard POST /api/tools/clipboard/set(ClipInject)+ u2 input
de_ui_tree GET /api/uiauto/…(或 core 直连)
de_ocr core.ocr(进程内或新只读端点)
de_list_devices GET /api/status + /api/devices/pool
de_open_app core device app_start(或任务层 open_app 动作)
de_screen_state dumpsys(core.common._device_screen_state)

实现时对平台缺失的只读入口(如 ocr/open_app 的直连面)优先在平台加只读端点(复用现有权限体系),MCP 不越权直连设备。