Files
auto_control/doc/MCP.md
T
butubb fd829a6063 docs: doc/ 全量同步 dev 现状——API 目录补全(AI 控制台/系统备份/自动发现等)、去 STF 过时口径、补 generic_steps 与配置键速查;确立「功能/配置改动须同步文档」红线
- doc/API.md:补方法/路径标题,权限分层修正,新增 AI 控制台(/api/agent/*)、系统备份(/api/system/backup/*)、设备自动发现(/api/devices/discovery/*)、tap_text/summary/health/devices-apps 等整节端点,去 STF 残留
- doc/TASK_DEV.md:STF 时代描述清理;新增 §2.10 generic_steps(18 节点与必填/嵌套/静默跳过语义)、§2.11 自定义动作与单步测试、/api/jobs 盲存校验语义、resolve_serials/抢占语义、模板构造函数签名修正
- doc/DEPLOY.md:数据备份改为推荐「系统→数据备份」功能并说明重启生效目录,端口表 STF7100→MCP8033,补 start.sh 生产链路与 MCP_PLATFORM_PASS 同步,故障排查去 STF
- doc/MCP.md:加「现状边界」(平台级任务 CRUD 未 MCP 化,规划见 AI_TASK_GEN §9),busy/平台会话说明,MCP_ALLOWED_SERIALS 语义纠正
- doc/MCP_DESIGN.md:加实现现状对照、错误码、独立容器改演进备选、里程碑状态、API 映射表按实现重写
- doc/ARCHITECTURE.md:Tab/子分栏/线程模型/数据表/蓝图表去 STF,补 device_discovery/agent/system_backup/经验巡检等
- doc/DEVELOPMENT.md:新增 §5.6「改动必须同步文档」红线、§2.3 配置键速查、蓝图化新增 API 流程、文档索引补登记
- doc/STF_REMOVAL.md:加历史记录状态横幅
- doc/AI_TASK_GEN.md:新增 AI 建任务设计稿(含 §9 需转 MCP 工具分层)
2026-09-09 16:05:56 +08:00

10 KiB
Raw Blame History

MCP 手机控制 Server(mcp_server/)

多模态 AI(DeepSeek/Claude 等)通过 MCP(Model Context Protocol) 实时操作 Android 手机的统一出口。AI 控制台(mcp_agent/)与外部 MCP 客户端都经它控制设备池中的手机。

本文档 = 使用手册(工具清单/用法)。架构与演进设计见 MCP_DESIGN.md。

架构

AI 控制台 / 外部 MCP 客户端
        │  Streamable HTTP
        ▼
MCP Server  (:8033, mcp_server/mcp_server.py)     ← 19 个 de_* 工具
        │  平台 HTTP API(登录 + CSRF)
        ▼
auto_control 平台 (:18050)                        ← 设备池/任务/看屏
        │  adb / uiautomator2 / uiautodev / OCR
        ▼
Android 设备(IP:5555)
  • 轻量通道直连(adb monkey 开 App、u2 输入、本地 OCR)不绕平台,省时省 token
  • 坐标换算、UI 吸附、剪贴板注入等细节全部在 Server 层消化,模型只需给意图

运行与配置

服务跑在 220 的 python-app 容器内(scripts/start.sh 自动拉起,端口 8033)。 生产访问方式:http://192.168.20.220:8033/mcp;本机调试 python3 -m mcp_server.mcp_server。

环境变量 默认 说明
MCP_PLATFORM_URL http://127.0.0.1:18050 平台地址(Agent 与平台同机时用本机)
MCP_PLATFORM_USER / MCP_PLATFORM_PASS admin / start.sh 兜底 admin123(手动直跑时默认空) 平台登录账号
MCP_ALLOW_WRITE 0 写门控:=1 才允许点击/输入/开关 App 等写操作(只读工具不受限)
MCP_ALLOWED_SERIALS 空 设备白名单(逗号分隔):非空=只允许列出的 serial;为空时代码只校验 serial 非空、不校验是否在平台设备池内(设计稿语义未实现)
MCP_HTTP_HOST / MCP_HTTP_PORT 0.0.0.0 / 8033 监听地址
MCP_SCREENSHOT_WIDTH 540 截图返回宽度上限(px),模型看到的图即该坐标系
MCP_JPEG_QUALITY 70 截图 JPEG 质量
MCP_AUDIT_FILE /var/log/mcp/audit.log 审计日志(每次工具调用一行)
MCP_PLATFORM_TIMEOUT 30 平台请求超时(秒)

生产(220 容器)已设 MCP_ALLOW_WRITE=1;MCP_ALLOWED_SERIALS 未设(= 代码只校验 serial 非空,不限制到平台设备池内;如需收紧请配置白名单)。

MCP_ENABLED:由 scripts/start.sh 消费(默认 1,=0 可关掉后台拉起的 MCP)。 MCP_PLATFORM_PASS:start.sh 兜底 admin123——改过平台 admin 密码必须同步该变量,否则 MCP 登录平台失败。 supervise.sh 不拉起 MCP:只守护 web_server;容器场景 MCP 由 start.sh 后台拉起(见 DEPLOY §2.4)。

坐标空间(重要约定)

  • de_screenshot 返回 ≤540px 宽的 JPEG(display 空间),并附 native_size(设备原生分辨率)
  • de_tap / de_swipe 的坐标一律使用 de_screenshot 返回图像的坐标系,Server 按比例换算为原生坐标
  • 先截图、后点击:Server 需要最近一次截图才能建立坐标空间(未截图就点击会报「请先执行 de_screenshot」)
  • de_tap 带自动吸附:点击点若落在某个可点击元素内,实际会点该元素中心——坐标只需大致对准,偏十几像素也能点准;点空白处则按原坐标
  • 返回的 snapped/label 可核对吸附结果(snapped=true 表示已吸到元素,label 为该元素文案)

工具清单(19 个)

设备与状态

工具 用途
de_list_devices 列出可控制设备:serial / 型号 / 在线 / 任务状态 / 前台 App。开局第一步
de_foreground_app(serial) 当前前台 App 包名(dumpsys,MIUI 焦点为空时自动兜底)

观察屏幕(感知)

工具 用途
de_screenshot(serial) 截图并返回图像(≤540px JPEG)+ 尺寸 + 亮/熄屏状态。多模态模型直接看图
de_ui_tree(serial, limit=150) 当前界面元素树(text/id/desc/class/bounds)。可点击元素排前;limit 1-300 控制条数防 token 膨胀。用于确认界面上有什么
de_ocr(serial) OCR 识别当前屏幕文字(UI 树没有的图片/WebView 文字也能识别),返回 [{text, score}]

点击与滑动(操作)

工具 用途
de_tap_text(serial, text) 按屏幕文字点击(推荐):给一个屏幕上可见的文字(子串匹配)即找到并点其中心。原生控件走 UI 树,WebView/图片文字自动 OCR 兜底。找不到返回明确错误
de_tap_element(serial, by, value, index=1) 按元素点击:by = text / id / desc(精确)或 text_contains / desc_contains(模糊)。多命中用 index 取第几个
de_tap(serial, x, y) 坐标点击(截图坐标系,自动吸附,见上)。纯图形目标(视频画面/无文字图标)才用它
de_swipe(serial, x1,y1,x2,y2, duration=0.2) 滑动(截图坐标系;长按=同点起止 + duration≥1)
de_press_key(serial, key) 按键:back / home / recent / menu / power / volume_up / volume_down / enter / delete / search / camera

输入与剪贴板

工具 用途
de_type_text(serial, text) 向当前界面输入框输入文字(支持中文,直设 EditText 不依赖剪贴板/粘贴)
de_set_clipboard(serial, text) 写入设备剪贴板(ClipInject 通道注入 + 读回验证)
de_read_clipboard(serial) 读取设备当前剪贴板内容

App 管理(轻量 adb 直连,不建 u2 会话)

工具 用途
de_open_app(serial, package) 打开 App(adb monkey 直启,无需知道 activity——最快的打开路径)
de_stop_app(serial, package) 强制停止 App(am force-stop)
de_list_apps(serial, keyword="") 列出第三方已装应用(pm list packages -3),keyword 可过滤(如 "douyin")

上表三个工具走 direct_ops 轻量 adb 直连(monkey / am force-stop / pm list packages),不建 u2 会话。

亮屏与熄屏(平台 screen_all 通道)

工具 用途
de_sleep(serial) 熄屏(运行中任务会中断,慎用)
de_wake(serial) 亮屏并解锁(熄屏时先调它再截图)

de_sleep/de_wake 走平台 POST /api/device/screen_all(platform_client),同样不在 MCP 进程内建 u2 会话。

平台联动

工具 用途
de_list_tasks() 列出平台任务计划(名称/类型/启用/调度),了解已自动化的工作

现状边界

本 Server 目前只有设备层的 de_*(控制/感知/只读)+ 平台只读的 de_list_tasks;平台级任务增改/提交/CRUD、分组/设备池/自定义动作/APK/备份等 REST 路由只给 Web 前端用,未暴露 MCP 工具。

补齐分层规划见 AI_TASK_GEN.md §9。每新增/修改/删除一个 MCP 工具或平台配置,必须同步更新本手册与 MCP_DESIGN.md(doc 同步红线)。

推荐使用模式(操作手机的正确姿势)

  1. de_list_devices 确认目标设备在线
  2. de_screenshot 看图理解当前界面(图像会在下一次模型回合送达)
  3. 点击定位优先级(从高到低):
    • 目标有可见文字 → de_tap_text(一次调用完成「找到并点击」,最可靠)
    • 文字有歧义/多候选 → de_ui_tree 确认后 de_tap_element(text_contains 模糊匹配)
    • 纯图形目标 → de_tap 坐标(无需精算,Server 自动吸附到可点元素中心)
  4. 输入文字:先点中输入框(de_tap_text / de_tap),再 de_type_text
  5. 每次关键操作后 de_screenshot 验证:界面变化 = 成功;无变化 = 未命中,换 de_tap_text / de_tap_element 重新定位,不要重复点同一坐标
  6. 完成/失败时用中文总结:做了什么、当前状态、注意事项
  7. 效率约束:界面未变不重复截图/点同位置;连续 6 步无进展停止并总结

安全与审计

  • 写门控:MCP_ALLOW_WRITE=0(默认)时点击/输入/开关 App 全部拒绝,只读工具可用
  • 任务占用互斥:写工具操作前调 _ensure_device_free 检查设备 worker_status,running/connecting 直接拒 device_busy(只读工具不受限),AI 不与任务抢设备
  • 平台会话 + CSRF:平台登录与会话由 platform_client 内部处理(MCP_PLATFORM_USER/PASS 登录拿 cookie、失效自动重登;POST 自动带 X-CSRF-Token),不向客户端暴露平台凭据
  • 设备白名单:MCP_ALLOWED_SERIALS 非空时限制可操作的 serial;空名单时代码只校验 serial 非空,不按平台设备池过滤
  • 审计日志:每次调用记录 {ts, tool, serial, args, result} 到 MCP_AUDIT_FILE(220 上 /tmp/mcp_audit.log)
  • 操作对象限定平台设备池;adb kill-server / adb disconnect 属项目红线,任何工具不触碰

客户端接入示例

import asyncio
from fastmcp import Client

async def main():
    async with Client("http://192.168.20.220:8033/mcp", timeout=30) as c:
        devs = await c.call_tool("de_list_devices", {})
        serial = devs.data["data"][0]["serial"]          # 取第一台在线设备
        shot = await c.call_tool("de_screenshot", {"serial": serial})
        img = shot.data["data"]["image"]                 # base64 JPEG(多模态模型可直接看图)
        await c.call_tool("de_tap_text", {"serial": serial, "text": "搜索"})

asyncio.run(main())

AI 控制台(内置 Agent)

Web 端「AI 控制台」Tab 内建的 Agent(mcp_agent/,OpenAI 兼容协议:DeepSeek 等)也通过本 Server 的同一批工具跑任务:

  • 流式输出 + 每步 MCP 工具调用实时展示(含截图缩略)
  • 多轮会话记忆(同会话上下文保留,新建会话清空)
  • 自进化经验记忆:一轮成功操作会被提炼成「配方」存入 agent_experience 表,下次相似任务自动注入参考(命中/写入均有 🧠 提示卡)
  • 模型与 API Key 在 AI 控制台右上角 ⚙ 配置,存平台 app_meta