内容
# pymobile-mcp
纯Python [MCP](https://modelcontextprotocol.io/) 服务器,用于移动自动化。
- **Android**: `uiautomator2` + `adbutils`
- **iOS**: 纯 `pymobiledevice3` 用户空间隧道 + WebDriverAgent(无 go-ios,无 root)
公共合约:固定上游 `mobile-mcp@c5d7d27` — **默认 23 个工具**,**启用 `MOBILEFLEET_ENABLE=1` 时为 26 个工具**。
`mobile_get_page_source` 不是公共的;fleet 运行时在没有安装 Python fleet 提供程序时使用记录的批准例外。
[](https://github.com/ByteTrue/pymobile-mcp/actions/workflows/ci.yml)
[](https://github.com/ByteTrue/pymobile-mcp/releases/latest)
[](https://pypi.org/project/pymobile-mcp/)
[](https://www.python.org/downloads/)
[](LICENSE)
当前版本:**0.3.0** · [变更日志](CHANGELOG.md) · [实时回归检查清单](docs/regression-checklist.md)
## 功能
- 一个用于 **Android + iOS** 的标准输入输出 MCP 服务器
- 与上游兼容的自然语言/图像结果和确切的可操作与 `isError=true` 失败
- 当设备丢失时,实时烟雾测试脚本会退出 `blocked`(代码 2)- 永远不会伪造通过
- 销毁操作(安装/卸载)由显式环境标志控制
## 要求
| 平台 | 需要 |
|---|---|
| 主机 | Python **≥ 3.10**,`pip` |
| Android | `adb` 在 `PATH` 中,授权设备或模拟器 |
| iOS | 推荐 macOS,配对的 iPhone/iPad,**开发者模式**,挂载 DDI,安装 WDA 运行器(默认 `com.byte.WebDriverAgentRunner.xctrunner`) |
> [!NOTE]
> iOS 真机屏幕录制在当前的纯用户空间 RSD(iOS 26.5.2)上返回批准的上游兼容异常。iOS 模拟器使用 `simctl recordVideo` + WDA,不受该异常覆盖。
## 安装
### 从 git 检出(开发)
```bash
git clone https://github.com/ByteTrue/pymobile-mcp.git
cd pymobile-mcp
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e .
pymobile-mcp --help
```
### 开发安装(测试)
```bash
pip install -e ".[dev]"
python -m pytest -q
```
### 从 PyPI
```bash
pip install pymobile-mcp==0.3.0
```
### 从 GitHub(无本地工具克隆)
```bash
pip install "git+https://github.com/ByteTrue/pymobile-mcp.git@v0.3.0"
```
> [!TIP]
> 优先使用虚拟环境。系统 Python + `pip install` 通常与 Homebrew/PEP 668 冲突。
## 快速开始
1. 连接 Android 模拟器/设备(`adb devices`)和/或配对的 iPhone。
2. 对于 iOS,确保 WDA 运行器已安装(Xcode 一次);pymobile-mcp 通过用户空间隧道启动它。
3. 运行服务器:
```bash
pymobile-mcp run
# 等效:
python -m pymobile_mcp.cli run
```
4. 将 MCP 客户端指向进程(标准输入输出)。
### MCP 客户端配置
**已安装入口点**(`pymobile-mcp` 在 `PATH` 上):
```json
{
"mcpServers": {
"pymobile-mcp": {
"command": "pymobile-mcp",
"args": ["run"]
}
}
}
```
**检出 / 虚拟环境**(绝对路径对 GUI 客户端更可靠):
```json
{
"mcpServers": {
"pymobile-mcp": {
"command": "/ABS/PATH/pymobile-mcp/.venv/bin/python",
"args": ["-m", "pymobile_mcp.cli", "run"],
"cwd": "/ABS/PATH/pymobile-mcp",
"env": {
"NO_PROXY": "*",
"PYTHONPATH": "src"
}
}
}
}
```
> [!IMPORTANT]
> 对于 iOS USB,请取消设置或绕过 HTTP 代理(`NO_PROXY=*` 或清除 `http_proxy`/`https_proxy`)。代理环境通常会破坏 usbmux / 用户空间隧道。
## 首选工具
客户端连接后:
1. `mobile_list_available_devices` — 确认 Android/iOS id
2. `mobile_get_screen_size` / `mobile_take_screenshot`
3. `mobile_list_elements_on_screen` — UI 树(无原始页面源工具)
4. `mobile_list_apps` → `mobile_launch_app` 使用已知的包/捆绑 ID
## 功能矩阵(23 个默认工具;启用 fleet 环境时为 26 个工具)
| 状态 | 含义 |
|---|---|
| **支持** | 已实现并涵盖自动合约测试;此标签不是当前设备实时认证的声明 |
| **批准的例外** | 显式审查的黑盒差异,具有稳定的上游兼容文本 |
当前实时证据在 Android 物理设备、Android 模拟器、iOS 模拟器和 iOS 真机上通过。Android 录制和 iOS 模拟器录制均通过实时测试;iOS 真机录制仍是批准的例外。
| 工具 | Android | iOS |
|---|---|---|
| mobile_list_available_devices | 支持 | 支持 |
| mobile_list_apps | 支持 | 支持 |
| mobile_launch_app | 支持 | 支持 |
| mobile_terminate_app | 支持 | 支持 |
| mobile_install_app | 支持(破坏性) | 支持(破坏性, gated) |
| mobile_uninstall_app | 支持(破坏性) | 支持(破坏性,gated) |
| mobile_get_screen_size | 支持 | 支持 |
| mobile_click_on_screen_at_coordinates | 支持 | 支持 |
| mobile_double_tap_on_screen | 支持 | 支持 |
| mobile_long_press_on_screen_at_coordinates | 支持 | 支持 |
| mobile_list_elements_on_screen | 支持 | 支持(WDA 源内部) |
| mobile_press_button | 支持 | 支持(`HOME`/`VOLUME_*`;`BACK` 不支持) |
| mobile_open_url | 支持(http/https 默认) | 支持(设备必须解锁) |
| mobile_swipe_on_screen | 支持 | 支持 |
| mobile_type_keys | 支持 | 支持 |
| mobile_save_screenshot | 支持 | 支持 |
| mobile_take_screenshot | 支持 | 支持 |
| mobile_set_orientation | 支持 | 支持 |
| mobile_get_orientation | 支持 | 支持 |
| mobile_start_screen_recording | 支持;实时通过 | 模拟器支持/实时通过;真实设备 **批准的例外** |
| mobile_stop_screen_recording | 支持;实时通过 | 模拟器支持/实时通过;真实设备 **批准的例外** |
| mobile_list_crashes | 支持(dropbox) | 支持(崩溃报告) |
| mobile_get_crash | 支持(dropbox) | 支持(崩溃报告) |
## 环境变量
| 环境变量 | 目的 |
|---|---|
| `MOBILEMCP_ALLOW_UNSAFE_URLS=1` | 允许 `mobile_open_url` 使用非 http(s) 方案 |
| `MOBILEFLEET_ENABLE=1` | 暴露上游 fleet 工具集(26 个工具);运行时在没有 Python fleet 提供程序时返回批准的例外 |
| `PYMOBILE_MCP_ANDROID_DROPBOX_ALL=1` | 包括非崩溃 dropbox 标签(strictmode/boot/…) |
| `PYMOBILE_MCP_ANDROID_DEVICE` | 固定 Android 序列号用于烟雾测试 |
| `PYMOBILE_MCP_ANDROID_ACTIONS=1` | 在 Android UI 烟雾测试中启用点击/输入交互 |
| `PYMOBILE_MCP_ANDROID_TAP=x,y` | 重写 Android 点击点 |
| `PYMOBILE_MCP_ANDROID_APK` + `PYMOBILE_MCP_ANDROID_PACKAGE` + `PYMOBILE_MCP_ANDROID_DESTRUCTIVE=1` | 允许安装/卸载烟雾测试 |
| `PYMOBILE_MCP_IOS_DEVICE` | 固定 iOS UDID |
| `PYMOBILE_MCP_IOS_ACTIONS=1` | 在 iOS 核心烟雾测试中启用交互步骤 |
| `PYMOBILE_MCP_WDA_XCTRUNNER` | WDA 运行器捆绑 ID(默认 `com.byte.WebDriverAgentRunner.xctrunner`) |
| `PYMOBILE_MCP_WDA_HOST` / `PYMOBILE_MCP_WDA_PORT` | 旧 WDA HTTP 端点旋钮(用户空间路径优先使用进程内服务客户端) |
| `PYMOBILE_MCP_IOS_IPA` + `PYMOBILE_MCP_IOS_DESTRUCTIVE=1` | 允许 iOS 安装/卸载烟雾测试 |
| `NO_PROXY=*` | iOS USB / usbmux 推荐 |
## 实时烟雾测试
脚本打印 JSON,状态为 `passed|failed|blocked`。
**退出 `2` + `blocked` = 设备/环境丢失,不是产品通过。**
```bash
export NO_PROXY='*'
PATH=.venv/bin:$PATH
# Android
python tests/android_live_smoke.py
PYMOBILE_MCP_ANDROID_ACTIONS=1 python tests/android_live_smoke.py
python tests/android_app_system_live_smoke.py
python tests/android_recording_crash_live_smoke.py
# iOS(解锁手机以打开网址)
python tests/ios_pmd3_wda_live_smoke.py
PYMOBILE_MCP_IOS_ACTIONS=1 python tests/ios_pmd3_wda_live_smoke.py
python tests/ios_system_helpers_live_smoke.py
python tests/ios_app_lifecycle_live_smoke.py
python tests/crash_tools_live_smoke.py
python tests/ios_app_recording_crash_live_smoke.py # 真实录制使用批准的例外
```
完整的双设备门控:[docs/regression-checklist.md](docs/regression-checklist.md)。
## 架构(简要)
```
MCP 客户端 --stdio--> pymobile-mcp 服务器
│
├─ 工具/注册表 + 规范 (23 个默认 / 26 个 fleet 合约)
├─ 工具/* 处理程序
└─ 驱动程序/
├─ android.py (adbutils / uiautomator2)
├─ ios.py (UserspaceRsdTunnel + WDA)
└─ ios_simulator.py (simctl + WDA)
```
## 开发
```bash
pip install -e ".[dev]"
python -m pytest -q
```
CI 在 Python 3.11 和 3.12 上运行单元测试([工作流](.github/workflows/ci.yml))。设备实时烟雾测试保留在本地。
## 已知限制
- Android 崩溃来自 `dumpsys dropbox --print`,默认过滤到崩溃/ANR/tombstone 类标签
- iOS 真机录制仍是批准的例外;模拟器录制需要启动的 CoreSimulator + WDA
- 录制状态是进程本地的(`ActiveRecording`);无跨进程恢复
- 自定义 URL 方案需要 `MOBILEMCP_ALLOW_UNSAFE_URLS=1`
- 截图/录制主机路径必须在 cwd 或系统临时目录下解析
- 无 go-ios/mobilecli 运行时回退,按设计
## 故障排除
| 症状 | 检查内容 |
|---|---|
| iOS 设备列表为空 | 电缆/信任,`pymobiledevice3 usbmux list`,代理(`NO_PROXY=*`) |
| iOS 驱动程序隧道错误 | 开发者模式,`pymobiledevice3 mounter auto-mount`,仅一个用户空间隧道进程 |
| `open_url` 在 iPhone 上失败 | 解锁设备(密码锁阻止 Safari/WDA 网址打开) |
| Android 设备为空 | `adb devices` 授权;杀死离线 `adb` 如果它处于离线状态 |
| 安装/卸载烟雾测试跳过 | 设置包/apk/ipa **和** `*_DESTRUCTIVE=1` |
| CI 绿色但实时红色 | 预期 — CI 仅限单元测试;使用 [回归检查清单](docs/regression-checklist.md) |