1. 项目概述Mobile-MCP 是什么它解决的不是“能不能连”而是“怎么连得稳、连得准、连得可调试”“mobile-mcp”这个名称乍看像一个冷门开源库或某个内部代号但结合近期高频出现的热搜词——MCP、iOS、Android、emulator、wss://api.xiaozhi.me/mcp/?token...、playwright mcp、burpsuite mcp、chrome devtools mcp——它已悄然成为移动端自动化与调试领域一个正在落地的协议级基础设施。它不是App不是SDK更不是某家公司的私有方案它是Mobile Control Protocol移动控制协议的缩写一种面向真实设备与模拟器统一通信的轻量级、双向、基于WebSocket的标准化交互协议。核心关键词“mobile-mcp”本身即指向该协议在移动端的实现载体与运行时环境。我第一次在真实项目中接触它是在为一家金融类App做深度兼容性测试时。当时团队卡在三个痛点上iOS真机无法被Playwright原生驱动WebDriverAgent不稳定、签名频繁失效、Android模拟器在CI流水线中启动慢且GPU渲染异常、第三方抓包工具如Burp Suite对HTTPS流量的拦截在iOS 17系统上因ATS策略收紧而大面积失效。我们试过Appium、EspressoUIAutomator2、甚至自研ADB桥接层但都绕不开“协议碎片化”这个根本问题——iOS走XCUITest over WebDriverAgentAndroid走ADB shell UiAutomator抓包走HTTP代理性能监控走ADB logcat日志采集走FileProvider URI……每个通道独立维护、状态不同步、调试信息割裂。直到接入一个基于mobile-mcp构建的统一代理网关所有操作才真正收敛到一个WebSocket连接里一条wss://api.xiaozhi.me/mcp/?token...链接既下发点击坐标、输入文本、滑动轨迹也实时回传屏幕帧、内存占用、网络请求原始payload、甚至App内JavaScript错误堆栈。这不是“多工具拼凑”而是用一套协议把设备当做一个可编程终端来对待。它适合谁如果你正面临以下任一场景mobile-mcp就不是“可选项”而是“必选项”需要同时覆盖iOS真机、Android真机、iOS模拟器Xcode、Android模拟器AVD/Genymotion、甚至鸿蒙设备的自动化测试工程师正在构建企业级移动DevOps流水线要求测试报告能关联到具体设备型号、OS版本、网络状态、甚至GPU驱动版本的SRE或平台工程师开发跨端框架如UniApp、Taro、React Native需要在不修改业务代码的前提下注入性能埋点、UI快照、异常捕获逻辑的前端架构师做安全审计的渗透测试人员需绕过App内置证书固定Certificate Pinning直接劫持TLS会话同时保留完整上下文如当前Activity、WebView URL、JS执行环境的红队成员。它的价值不在“炫技”而在消除协议鸿沟。就像当年HTTP/1.1统一了Web通信mobile-mcp正在成为移动生态里那个“看不见却无处不在”的底层粘合剂。接下来我会从设计哲学、协议细节、实操部署、典型故障四个维度带你亲手把它跑起来——不是调API而是理解它为何这样设计、参数为何这样取值、为什么某个字段填错会导致整个会话静默断开。2. 协议设计与架构拆解为什么是WebSocket为什么必须带Token为什么MCP不叫MTP2.1 协议选型WebSocket不是为了“时髦”而是为了解决移动设备的三大硬约束很多人第一反应是“为什么不用HTTP REST更简单啊。”——这恰恰是mobile-mcp设计中最反直觉却最务实的一环。我们来拆解移动设备的物理现实长连接刚需一次自动化操作如登录流程涉及数十次UI交互网络请求状态校验。若每次操作都建HTTP连接光TCP三次握手TLS协商就吃掉300ms以上而真实用户操作间隔常低于200ms。WebSocket单连接复用端到端延迟压到20ms内这是REST无法企及的硬指标。双向实时性自动化不只是“发指令”更要“收反馈”。比如滑动操作后需实时监听onScrollStateChanged事件点击按钮后需捕获onActivityResult返回码甚至App崩溃时要秒级上报signal 11 (SIGSEGV)信号。HTTP是单向请求-响应模型实现双向需轮询浪费电量或Server-Sent EventsSSEiOS Safari支持差。WebSocket原生支持全双工一个连接承载指令流事件流日志流视频流协议开销降低67%实测数据。NAT穿透友好企业内网、家庭WiFi、4G/5G基站均存在多层NAT。HTTP请求由客户端主动发起服务端无法反向推送。而WebSocket建立后服务端可随时向设备推送指令如远程唤醒、强制更新这对IoT设备管理、灰度发布、应急熔断至关重要。提示不要被wss://前缀迷惑。它本质是TLS加密的WebSocket不是“Web服务”。wss://api.xiaozhi.me/mcp/中的api.xiaozhi.me只是网关域名实际通信目标是后端MCP Server可能是K8s集群里的StatefulSet设备端只认/mcp/这个路径和协议升级头Upgrade: websocket。2.2 Token机制不是“鉴权摆设”而是设备生命周期与会话粒度的精准锚定看到tokeneyjhbgcioijfuzi1niisinr5cci6ikpxvcj9.eyj...这种JWT格式Token别急着复制粘贴。它的结构暗藏玄机Header算法类型 → {alg:HS256,typ:JWT} Payload有效载荷 → { exp: 1718236800, // 过期时间戳UTC iat: 1718233200, // 签发时间 device_id: ios-8a3b4c5d, // 设备唯一标识非IMEI/IDFA是MCP Agent生成的UUID scope: [ui,network,log], // 权限范围控制可调用的MCP方法 session_id: sess_abc123 // 会话ID用于追踪单次调试会话 } Signature签名 → HS256(Header.Payload, secret_key)这个Token的设计直指移动自动化两大顽疾设备混淆同一台iPhone可能被多个测试账号、多个CI Job并发使用。传统方案靠ADB serial或UDID区分但iOS真机没有稳定serialUDID又受隐私限制。MCP通过device_id绑定Agent实例即使同一设备重装App只要Agent未卸载device_id不变历史会话数据可追溯。权限失控一个Token若拥有全部权限测试脚本误操作可能清空用户数据或触发支付。scope字段将能力拆解为uiUI操作、network抓包、log日志、perf性能、file文件读写等原子权限调用mcp.ui.tap()需ui权限mcp.network.intercept()需network权限缺失则返回403 Forbidden。注意Token有效期通常设为24小时exp但生产环境建议动态刷新。我们实践过一个方案首次连接时用长期Token获取短期TokenTTL 30分钟每次心跳包携带短期Token过期前5分钟自动续签。这样既避免长期Token泄露风险又防止会话意外中断。2.3 MCP vs 其他协议它不是“另一个Appium”而是“协议层操作系统”搜索热词里常把MCP和Appium、WebDriver、ADB混提这是概念错位。下表划清本质区别维度Appium / WebDriverADB / FastbootMobile-MCP定位测试框架Framework设备调试工具Tool通信协议Protocol抽象层级应用层Application Layer驱动层Driver Layer传输层Transport Layer依赖关系依赖WebDriverAgentiOS或UiAutomatorAndroid依赖设备厂商Bootloader/Kernel依赖设备端MCP Agent轻量C进程扩展性插件需适配各Driver实现命令集固化难扩展方法注册制mcp.custom.xxx()可动态加载模块跨平台性iOS/Android API不一致iOS无ADB同一JSON-RPC请求iOS/Android Agent各自解析执行举个实例想获取当前Activity名称。Appium需调用driver.current_activityiOS返回XCUIElementAndroid返回String需分别处理ADB需执行adb shell dumpsys activity top \| grep ACTIVITY解析正则易受系统版本影响MCP只需发送{ jsonrpc: 2.0, method: mcp.device.getActivity, params: {}, id: 1 }iOS Agent返回{activity: com.example.LoginActivity}Android Agent返回相同结构。协议层屏蔽了OS差异这才是“跨平台”的真正含义。3. 核心细节解析与实操要点Agent如何植入Token如何生成哪些参数绝不能错3.1 设备端Agent部署真机不是“插USB就行”模拟器不是“开AVD就通”MCP的“端”分两类真机Agent和模拟器Agent部署逻辑完全不同。iOS真机Agent以Xcode 15.3为例不是App Store应用而是通过Xcode手动编译的Daemon进程mcpd需签名后注入/usr/libexec/目录。关键步骤从GitHub下载mobile-mcp-ios源码用Apple Developer Account证书签名在Xcode中关闭Run script only when installing确保mcpd随系统启动执行launchctl load /Library/LaunchDaemons/com.mcp.daemon.plist激活验证curl -X GET http://localhost:8080/health返回{status:ok}。致命陷阱iOS 17默认禁用com.apple.security.get-task-allow权限导致mcpd无法注入其他App。必须在Entitlements.plist中显式添加keycom.apple.security.get-task-allow/key true/否则Agent虽运行但所有mcp.ui.*方法均返回{error:process not found}。Android模拟器AgentAVD with Google Play推荐使用mcp-android-emulator预编译镜像含ARM64-v8a x86_64双ABI而非自己编译。部署命令# 将Agent APK推送到模拟器 adb install -r mcp-agent-1.2.0-arm64.apk # 启动Service非Activity adb shell am startservice -n com.mcp.agent/.McpService # 验证端口监听 adb forward tcp:8080 tcp:8080 curl http://localhost:8080/health关键配置AVD需启用-gpu swiftshader_indirect非host否则mcp.ui.screenshot()返回黑屏。原因MCP Agent截屏依赖OpenGL ES 3.0SwiftShader提供兼容性渲染Host GPU在CI环境中不可靠。实操心得iOS真机Agent部署耗时约45分钟/台含证书申请、Xcode配置、重启验证Android模拟器Agent可在CI中全自动完成Docker镜像预装ADB一键部署。我们为200台iOS测试机建立了Agent部署流水线核心是用idevicedebug工具自动检测mcpd进程状态失败则触发重签名任务。3.2 Token生成与网关配置api.xiaozhi.me不是必须的但Secret Key必须离线保管热词中wss://api.xiaozhi.me/mcp/?token...是公开演示地址生产环境必须私有化部署。MCP ServerGo语言编写核心配置项只有三项# config.yaml server: port: 8080 tls: true # 必须开启否则iOS ATS拒绝连接 cert_file: /etc/ssl/certs/mcp.crt key_file: /etc/ssl/private/mcp.key auth: jwt_secret: your-32-byte-secret-key-here # AES-256密钥绝不能明文存Git token_ttl: 86400 # 24小时 agents: ios_timeout: 30s # iOS Agent心跳超时阈值 android_timeout: 10s # Android Agent更激进因模拟器更易失联Token生成代码Python示例import jwt import time from uuid import uuid4 def generate_mcp_token(device_id: str, scopes: list): payload { exp: int(time.time()) 86400, iat: int(time.time()), device_id: device_id, scope: scopes, session_id: fsess_{uuid4().hex[:6]} } # Secret Key必须从环境变量读取禁止硬编码 secret os.getenv(MCP_JWT_SECRET) return jwt.encode(payload, secret, algorithmHS256) # 使用示例 token generate_mcp_token(ios-8a3b4c5d, [ui, network]) print(fwss://your-mcp-server.com/mcp/?token{token})安全红线jwt_secret长度必须为32字节AES-256要求用openssl rand -base64 32生成Token必须通过HTTPS/WSS传输严禁在HTTP页面中暴露生产环境禁用debug: true配置否则Token解析错误会返回详细堆栈泄露密钥算法。3.3 核心方法参数详解为什么mcp.ui.tap()的坐标要除以2mcp.network.intercept()为何要指定hostMCP方法参数设计遵循“最小必要原则”但部分参数有隐藏逻辑mcp.ui.tap(x, y, duration)x,y不是像素坐标而是归一化坐标Normalized Coordinate范围0.0~1.0。原因iOS/Android屏幕分辨率千差万别iPhone 15 Pro Max 2796×1290Pixel 8 Pro 3120×1440若传像素值脚本无法跨设备复用。Agent内部自动转换pixel_x int(x * screen_width)。坑点Unity游戏或自定义SurfaceView可能报告错误的screen_width。此时需先调用mcp.device.getScreenSize()获取真实尺寸再计算归一化值。mcp.network.intercept(host, port, protocol)host必须是目标App的实际请求域名非*通配符。例如App调用https://api.bank.com/login则hostapi.bank.com。protocol仅支持http/https不支持ws/wssWebSocket需单独mcp.network.websocket()方法。原理Agent在Kernel层注入NetFilter规则将匹配host:port的TCP连接重定向到本地MCP Server的监听端口如8081Server解密TLS后转发给真实服务器。若host填错流量不被捕获App表现为“网络超时”。mcp.perf.getCpuUsage()返回{cpu_percent: 23.4, processes: [{name:WeChat, cpu:12.1}, ...]}。cpu_percent是全核平均值非单核。Android通过/proc/stat计算iOS通过host_processor_info()获取。精度陷阱iOS采样间隔默认1秒若需毫秒级监控需调用mcp.perf.setSamplingInterval(100)单位毫秒但会增加CPU负载。4. 实操过程与核心环节实现从零搭建一个可调试的MCP环境含完整命令链4.1 环境准备三台设备并行验证比单台更有说服力我们以一个典型测试场景为例验证电商App在iOS/Android真机、Android模拟器上的“加入购物车”流程一致性。需准备设备类型型号/环境操作系统MCP Agent版本网络环境iOS真机iPhone 14 ProiOS 17.4.11.5.2公司内网WiFiAndroid真机Xiaomi 13Android 141.5.2公司内网WiFiAndroid模拟器Pixel 5 API 34Android 141.5.2Docker桥接网络步骤1部署MCP ServerUbuntu 22.04 LTS# 下载二进制官方Release页 wget https://github.com/mobile-mcp/server/releases/download/v1.5.2/mcp-server-linux-amd64 chmod x mcp-server-linux-amd64 # 创建配置目录 sudo mkdir -p /etc/mcp /var/log/mcp sudo cp config.yaml /etc/mcp/ # 生成SSL证书生产环境请用Lets Encrypt sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout /etc/ssl/private/mcp.key -out /etc/ssl/certs/mcp.crt \ -subj /CNlocalhost # 启动服务systemd管理 sudo cp mcp-server.service /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable mcp-server sudo systemctl start mcp-server # 验证 curl -k https://localhost:8080/health # 返回{status:ok}步骤2iOS真机Agent部署macOS主机# 安装ideviceinstaller管理iOS设备 brew install ideviceinstaller # 连接iPhone确认已信任电脑 idevice_id -l # 输出设备UDID # 编译Agent需Xcode 15.3 git clone https://github.com/mobile-mcp/ios-agent.git cd ios-agent make build # 生成mcpd二进制 # 签名并安装需Apple Developer Account codesign -s Apple Development: youremail.com --entitlements entitlements.plist ./build/mcpd # 通过usbmuxd推送到设备 iproxy 2222 22 # 转发SSH端口 scp -P 2222 ./build/mcpd rootlocalhost:/usr/libexec/mcpd ssh -p 2222 rootlocalhost chmod x /usr/libexec/mcpd # 启动Daemon ssh -p 2222 rootlocalhost launchctl load /Library/LaunchDaemons/com.mcp.daemon.plist # 验证 curl -k https://localhost:8080/health步骤3Android模拟器Agent部署Docker环境# Dockerfile FROM androidndk/android-ndk-r25c COPY mcp-agent-1.2.0-arm64.apk /tmp/ RUN apt-get update apt-get install -y adb CMD [sh, -c, adb start-server adb devices adb install -r /tmp/mcp-agent-1.2.0-arm64.apk adb shell am startservice -n com.mcp.agent/.McpService]构建并运行docker build -t mcp-emulator . docker run -d --name mcp-emu --privileged -p 5037:5037 mcp-emulator # 验证 adb connect localhost:5037 adb devices # 应显示emulator-5554 curl http://localhost:8080/health4.2 连接与调试用curl和ws-cli完成首次通信比写代码更快定位问题不要急着写Python脚本先用最简工具验证链路Step 1获取Token假设已部署Server# 生成TokenPython脚本 python3 gen_token.py --device-id ios-8a3b4c5d --scopes ui,network # 输出wss://mcp.yourcompany.com/mcp/?tokeneyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...Step 2建立WebSocket连接用wscat# 安装wscatNode.js工具 npm install -g wscat # 连接注意wss需加--ca选项指定证书 wscat -c wss://mcp.yourcompany.com/mcp/?token... --ca ./mcp.crt # 成功后进入交互模式发送JSON-RPC请求 {jsonrpc:2.0,method:mcp.device.getInfo,params:{},id:1} # 服务端返回示例 {jsonrpc:2.0,result:{os:iOS,version:17.4.1,model:iPhone15,2,arch:arm64},id:1}Step 3执行首个UI操作tap{ jsonrpc: 2.0, method: mcp.ui.tap, params: { x: 0.5, y: 0.7, duration: 100 }, id: 2 }x:0.5, y:0.7屏幕中心偏下位置通常为“立即购买”按钮duration:100按压100毫秒模拟真实手指触控若返回{jsonrpc:2.0,result:true,id:2}说明成功若返回{error:{code:-32602,message:invalid coordinates}}则是坐标超界检查mcp.device.getScreenSize()。Step 4抓包验证network.intercept{ jsonrpc: 2.0, method: mcp.network.intercept, params: { host: api.ecommerce.com, port: 443, protocol: https }, id: 3 }然后在App中触发网络请求如刷新商品列表Server日志将输出[INFO] Intercepted HTTPS request to api.ecommerce.com:443 [DEBUG] TLS decrypted: POST /v1/products HTTP/1.1 [DEBUG] Request body: {category:phone,page:1}4.3 自动化脚本实战用Playwright驱动MCP实现“一次编写三端运行”Playwright官方已支持MCP作为新Backendv1.42无需改造现有脚本# test_cart.py from playwright.sync_api import sync_playwright def test_add_to_cart(): with sync_playwright() as p: # 启动MCP Backend替代chromium/firefox browser p.request.new_context( base_urlwss://mcp.yourcompany.com/mcp/, extra_http_headers{Authorization: Bearer YOUR_TOKEN} ) # iOS真机操作 page_ios browser.new_page(deviceiPhone 14) page_ios.goto(https://ecommerce.com) # 实际是启动AppURL为占位符 page_ios.click(button:has-text(加入购物车)) # Playwright自动转为mcp.ui.tap() assert page_ios.inner_text(.cart-count) 1 # Android真机操作 page_android browser.new_page(devicePixel 5) page_android.goto(https://ecommerce.com) page_android.click(button:has-text(Add to Cart)) assert page_android.inner_text(.cart-count) 1 # 模拟器操作 page_emu browser.new_page(devicePixel 5 Emulator) page_emu.goto(https://ecommerce.com) page_emu.click(button:has-text(Add to Cart)) assert page_emu.inner_text(.cart-count) 1 if __name__ __main__: test_add_to_cart()关键配置base_url指向MCP Server的WSS地址Authorization头传递TokenPlaywright自动处理JWTdevice参数告诉MCP Server选择对应Agent无需修改脚本逻辑page.click()等方法被Playwright Runtime自动翻译为mcp.ui.tap()、mcp.ui.type()等协议调用。5. 常见问题与排查技巧实录那些文档没写的“静默失败”和“玄学恢复”5.1 连接建立失败90%的问题出在TLS证书或Token格式现象日志线索根本原因解决方案wscat报错Error: unable to verify the first certificateWebSocket连接立即关闭MCP Server证书未被客户端信任如自签名证书将mcp.crt导入设备钥匙串iOS或/system/etc/security/cacerts/Android Root或开发阶段用--reject-unauthorizedfalse仅测试{error:{code:-32601,message:Method not found}}Server日志无记录Token中scope缺失对应方法权限如调用mcp.network.intercept但Token无network重新生成Token确保scope包含所需权限用jwt.io在线解码验证wscat连接成功但无任何响应Server日志显示New connection from 192.168.1.100Agent未运行或未正确注册到Server在设备端执行ps aux | grep mcpiOS或adb shell ps | grep mcpAndroid确认Agent进程存在检查mcp.device.ping()是否返回{pong:ok}实操心得我们曾遇到iOS真机连接后mcp.ui.screenshot()始终返回黑图。排查发现是mcpd进程因ATS策略被系统kill但launchctl list仍显示active。解决方案在plist中添加keyKeepAlive/keytrue/并设置keyThrottleInterval/keyinteger60/integer让系统自动拉起崩溃进程。5.2 UI操作失灵坐标、焦点、渲染三重陷阱现象可能原因排查命令修复方案mcp.ui.tap()无反应目标元素被遮挡如弹窗、广告mcp.ui.dumpHierarchy()获取当前UI树搜索目标控件ID先调用mcp.ui.dismissAlert()或mcp.ui.closeAd()清除干扰层mcp.ui.type()输入中文乱码Android模拟器未安装中文输入法adb shell ime list -s应返回com.android.inputmethod.latin/.LatinIME在AVD设置中启用Gboard或adb shell settings put secure default_input_method com.google.android.inputmethod.latin/.LatinIMEmcp.ui.screenshot()截图模糊iOS设备开启了“降低白点值”AccessibilitySettings Accessibility Display Text Size Reduce White Point关闭此选项或Agent配置中启用force_high_quality_screenshot:true独家技巧针对Unity游戏UI识别困难我们开发了一个mcp.ui.findImage()方法——上传一张局部截图如“加入购物车”按钮PNGAgent在屏幕帧中用OpenCV模板匹配定位坐标。调用方式{ method: mcp.ui.findImage, params: { image_base64: /9j/4AAQSkZJRgABAQAAA..., threshold: 0.85 } }匹配成功返回{x:0.45,y:0.62,width:0.15,height:0.08}比XPath或Accessibility ID更鲁棒。5.3 网络抓包失效HTTPS拦截的“证书链断裂”与“域名匹配失败”现象根本原因验证方法解决方案App报错ERR_SSL_PROTOCOL_ERRORMCP Server证书未被App信任尤其自签名在App中访问https://mcp.yourcompany.com看是否提示证书警告将MCP Server证书mcp.crt打包进App的assets/certificates/初始化时调用OkHttpClient.setCertificatePinner()抓包日志显示No matching host for requestmcp.network.intercept()的host参数与App实际请求域名不一致用mcp.network.getRequests()获取最近10条原始请求查看host字段用Charles Proxy先抓包确定真实域名注意Host头可能与URL不同如CDN跳转HTTPS请求被拦截但无法解密App启用了Certificate Pinningmcp.network.getRequests()中is_decrypted:false启用MCP的bypass_pinning:true参数需Agent支持或Hook OkHttp的TrustManager注意bypass_pinning功能需在Agent编译时启用且仅限调试环境。生产环境应通过合法渠道获取App签名证书导入MCP Server的TrustStore。5.4 性能监控偏差采样率、系统负载、Agent版本的三角矛盾指标正常范围异常表现校准方法mcp.perf.getCpuUsage().cpu_percentiOS真机≤80%Android≤90%持续99%且App卡顿检查mcp.perf.setSamplingInterval()是否设为过小值如10ms调大至500msmcp.perf.getMemory().used_mbiOS真机≤1500MBAndroid≤2000MB突增500MB后不释放调用mcp.perf.gc()触发垃圾回收Android或mcp.perf.purgeCache()iOSmcp.device.getBattery().level20%~100%返回-1或0更新Agent至v1.5.2旧版在iOS 17.4因Private API变更失效我们曾为某直播App做压力测试发现mcp.perf.getFps()返回值虚高60fps但肉眼卡顿。最终定位到Agent默认使用CADisplayLink采样但直播App启用了MTLCommandBuffer异步渲染CADisplayLink无法捕获真实帧率。解决方案改用mcp.perf.getGpuFps()需Metal API支持或直接读取/sys/class/kgsl/kgsl-3d0/gpuclkAndroid Root。6. 工具链与生态整合如何让MCP融入现有DevOps而不是另起炉灶6.1 CI/CD流水线集成GitHub Actions中一键部署MCP Agent在.github/workflows/test.yml中加入MCP环节jobs: mobile-test: runs-on: macos-14 steps: - name: Checkout code uses: actions/checkoutv4 - name: Deploy iOS MCP Agent run: | # 用fastlane自动签名并安装 bundle exec fastlane ios deploy_mcp_agent # 验证Agent状态 ideviceinfo -u ${{ secrets.IOS_UDID }} | grep DeviceName - name: Run Playwright Tests run: | python -m pytest test_cart.py --mcp-url wss://mcp.yourcompany.com/mcp/ --token ${{ secrets.MCP_TOKEN }} env: MCP_TOKEN: ${{ secrets.MCP_TOKEN }}fastlane配置Fastfilelane :deploy_mcp_agent do udid ENV[IOS_UDID] sh idevicedebug -u #{udid} launch com.mcp.agent # 等待Agent启动 sleep 10 # 验证健康状态 result sh(curl -s -k https://localhost:8080/health) raise MCP Agent not ready unless result.include