mobile-mcp-allinone
# mobile-cli-allinone
由 [xue-ding-e](https://github.com/xue-ding-e) 维护的移动设备自动化工具。以 **CLI 的 `run` / `eval` 为主要脚本入口**,提供原生界面操作、Android WebView CDP 调试和 JSON 流程重放;另提供 MCP 服务供支持 MCP 的客户端使用。
仓库已从 `mobile-mcp-allinone` 更名为 `mobile-cli-allinone`,多平台源码与线性历史已推送到本仓库;以下链接和克隆示例使用当前名称。npm 包名 `@xue-ding-e/mobile-mcp-allinone`、MCP registry ID `io.github.xue-ding-e/mobile-mcp-allinone` 和 `mcp-server-mobile` 命令暂保持兼容,不表示发布了新包。
不同平台有不同的驱动和能力,不能把 Android 命令直接套到其他平台。下表描述当前源码接入情况,不代表已在所有系统、设备和版本上完成真机验收。
## 平台支持与边界
| 目标 | CLI | MCP | 所需驱动与限制 |
| --- | --- | --- | --- |
| Android 真机 / 模拟器 | 已接入原生操作、脚本、流程、WebView | 已接入 | ADB;设备须在线并授权。WebView 需应用开启调试 |
| HarmonyOS / OpenHarmony HDC 目标 | 已接入原生操作、脚本、原生流程 | 已接入设备发现、原生操作和原生流程 | HDC、设备调试授权以及设备侧 UITest / bm / aa 等命令;不是 Android ADB |
| iOS 真机 | 已接入原生操作、脚本、原生流程(`--platform ios`) | 已接入 | go-ios、设备信任/开发配置、WebDriverAgent(WDA);iOS 17+ 还需 tunnel |
| iOS Simulator | 已接入 Simctl / WDA(`--platform ios-simulator`);CLI 截图直接使用 Simctl | 已接入 mobilecli / agent | macOS / Xcode / 已启动的模拟器;CLI 与 MCP 驱动不同,不能在 Windows / Linux 本机运行 simctl |
- Android 专属:`wv-*`、脚本 `wv`、WebView 流程和 CLI 录屏。没有 iOS Safari / WKWebView 或 HarmonyOS WebView CDP 接入。
- HarmonyOS 支持控件读取、点击/双击/长按/滑动、文字输入、截图、应用启动/停止、签名 HAP 安装/卸载、文件传输与电源操作。长按时长由 UITest 决定,不支持自定义 duration;`url`、设置方向、录屏尚不支持。读取方向根据截图尺寸判断。
- HDC `install` 仅接受 `.hap`,不会把 APK 当 HAP 安装。卓易通等兼容环境里的 APK 导入和手机端安装需要单独处理。
- 默认 iOS 真机 go-ios 路径的 WDA 使用本机 `localhost:8100`,iOS 17+ tunnel 检查使用 `60105`。操作前必须确认该端口对应选定设备。CLI 模拟器不使用该共享端口,UI 控制必须提供独占 Runner 的显式绑定。
- CLI 模拟器的 `install` / `launch` / `shot` 不需要 WDA。`shot` 从显式 simulator UUID 写入本次独占的临时 PNG,读取并校验头部和尺寸后清理;它不依赖部分 simctl 版本行为不一致的 `-` stdout 输出,不选择 `booted` 默认设备,也不会启动或查询共享 WDA。尺寸/元素读取与点击等 UI 控制需要 `--simulator-wda-config`;缺失或身份不符时直接失败。Windows 应通过 SSH 在 Mac 上运行 CLI,工具没有内置远程 simctl 传输。
- MCP 的设备发现隔离不同驱动的失败;Android / HarmonyOS / iOS 真机的原生操作不要求先安装模拟器用的 mobilecli。MCP 录屏和崩溃报告仍使用 mobilecli,HarmonyOS 不支持这些工具。
- CLI iOS 不支持 `connect`、`wake`、`power-state`、`keep-awake`、文件传输和录屏。WDA 按键仅支持 `HOME`、`VOLUME_UP`、`VOLUME_DOWN`、`ENTER`,不能照搬 Android 的 `BACK`。CLI 与 MCP 的模拟器驱动分别为 Simctl / WDA 与 mobilecli / agent。
## 从源码安装
使用 **Node.js 22 或更高版本**以及 npm。各平台工具需要另行准备,不随此仓库自动完成设备授权、WDA 签名或 Xcode 配置。
```sh
git clone https://github.com/xue-ding-e/mobile-cli-allinone.git
cd mobile-cli-allinone
npm ci
npm run build
node lib/cli.js help
```
以上是本仓库源码安装方式,不假定 npm 包已经发布。修改 TypeScript 源码后重新执行 `npm run build`。
构建后也可把本地 checkout 安装到一个独立目录,使用新 CLI 别名(不修改全局安装):
```sh
npm install --prefix /path/to/local-install --ignore-scripts /path/to/mobile-cli-allinone
/path/to/local-install/node_modules/.bin/mobile-cli-allinone help
```
将路径替换成实际绝对路径;Windows 使用对应的 `.cmd` 垫片。此别名映射到 `lib/cli.js`;旧 `mcp-server-mobile` 仍映射到 `lib/index.js`。本地安装示例不表示新版已发布到 npm。
所有主机均可用 `node lib/cli.js` 启动 CLI。在 Windows PowerShell 中也可使用仓库垫片:
```powershell
.\mobile.ps1 help
.\mobile.ps1 devices --all
```
CLI 的目标平台由驱动决定;能启动 Node.js 不代表主机具备目标平台的完整工具链。
### 平台前置条件
- **Android**:安装 Android SDK Platform Tools,让 `adb` 可用,或设置 `ANDROID_HOME` 指向 SDK。手机开启调试并确认主机授权;模拟器先启动并确保出现在 `adb devices` 中。无线连接需要设备端预先配置,CLI 不代替配对和授权。
- **HarmonyOS**:安装适合主机的 HDC。可通过 `MOBILE_HDC_PATH` 指定可执行文件完整路径;未设置时,Windows 会尝试 HiSuite 的固定路径,随后回退到 PATH 中的 `hdc`。设备需支持相应 UITest 等命令并已授权。USB 标识和无线 `host:port` 是独立连接目标。
- **iOS 真机**:准备 go-ios,命令默认名为 `ios`,或以 `GO_IOS_PATH` 指定路径。先完成设备信任及所需开发配置、WDA 安装/运行、到本机 8100 的端口转发;iOS 17+ 还需运行 tunnel。程序检查这些前置状态,不会自动替你签名或部署 WDA。不同主机与 iOS 版本组合需自行验收。
- **iOS Simulator**:需要 macOS、Xcode 和已启动(Booted)的模拟器。CLI 用 `xcrun simctl` 发现和管理应用,UI 操作还需预先建立并绑定独占 WDA Runner;CLI 不会启动、安装或签名 Runner。MCP 则使用 mobilewright 依赖提供的 mobilecli,可用 `MOBILECLI_PATH` 指定二进制路径,首次原生操作可能检测并安装模拟器 agent。不要将 mobilecli 的跨平台二进制名称理解为 Windows 可运行 iOS Simulator。
## CLI 快速开始
示例中的设备 ID 和包名必须替换为自己的目标。建议先查看设备和界面,再执行会改变应用状态的命令。
```sh
node lib/cli.js devices --platform android --all
node lib/cli.js use ANDROID_SERIAL --platform android --pkg com.example.app
node lib/cli.js state
node lib/cli.js screen-size
node lib/cli.js elements
node lib/cli.js shot ./screen.png
```
`capabilities --platform android|harmony|ios|ios-simulator` 可查看各平台静态能力和依赖(命令中选择一个平台值);它不检查驱动安装、WDA 状态或设备是否就绪。
`use` 将默认设备、平台和包名写入当前用户的 `~/.mobile-cli/state.json`。命令行 `--device` / `--platform` / `--pkg` 可以覆盖默认值;自动选取唯一在线设备也会更新状态。多设备操作应显式传参,运行前用 `state` 核对旧状态。
HarmonyOS 示例:
```sh
node lib/cli.js devices --platform harmony --all
node lib/cli.js use HDC_TARGET --platform harmony
node lib/cli.js elements
node lib/cli.js launch com.example.app --ability EntryAbility
node lib/cli.js tap-text "设置"
node lib/cli.js shot ./harmony-screen.png
```
已配置无线调试的 HDC 目标可使用 `connect HOST:PORT --platform harmony`。`keep-awake 300`、`keep-awake restore` 以及 `file-send LOCAL REMOTE` / `file-recv REMOTE LOCAL` 是 HarmonyOS 专用扩展;`wake` / `power-state` 同时支持 Android 和 HarmonyOS。文件发送和电源设置会修改目标设备。
iOS 真机示例(已完成 go-ios / WDA / tunnel 前置配置):
```sh
node lib/cli.js capabilities --platform ios
node lib/cli.js devices --platform ios
node lib/cli.js use IOS_UDID --platform ios
node lib/cli.js elements
node lib/cli.js shot ./ios-screen.png
```
iOS Simulator 示例(仅 macOS,已启动模拟器):
```sh
node lib/cli.js devices --platform ios-simulator --all
node lib/cli.js launch com.example.app --platform ios-simulator --device SIMULATOR_UUID
node lib/cli.js shot /absolute/screen.png --platform ios-simulator --device SIMULATOR_UUID
node lib/cli.js wda-status --platform ios-simulator --device SIMULATOR_UUID --simulator-wda-config /private/simulator-wda.json
node lib/cli.js eval "return await robot.getScreenSize()" --platform ios-simulator --device SIMULATOR_UUID --simulator-wda-config /private/simulator-wda.json
```
`--all` 可显示未启动的模拟器,不代表它可以立即执行操作。CLI 不会自动创建/启动模拟器,也不会创建 iOS 无线连接或部署 WDA。模拟器安装使用适配模拟器的 `.app`,也支持顶层包含 `.app` 的 `.zip`;不能将真机 IPA 当作模拟器应用通用安装。
### Simulator 的独占 WDA 绑定
`--simulator-wda-config` 只接受显式 `--platform ios-simulator --device <完整 UUID>`。私有 JSON 的 `schemaVersion` 为 `1`,`simulatorUuid` 必须与命令一致,`wdaOrigin` 为独占数字 loopback HTTP origin,须显式端口且不能使用共享 `8100`。配置不写入全局默认,也不适用于物理 iOS 的 `--ios-config`。
`runner` 必填 `bundleId`(以 `.xctrunner` 结尾)、`pid`、`processStart`(实际 `ps -p PID -o lstart=`)、`executableSha256`、`wdaProductBundleIdentifier` 和 `codeFiles`。每项代码包含安装 bundle 内的 `relativePath` 与小写 `sha256`;应从本次独占构建枚举完整 Mach-O 清单并安装回读。至少包含 XCTest 主执行文件和 `WebDriverAgentLib.framework/WebDriverAgentLib`,两项还须提供实际加载的绝对 `mappedPath`。XCTest 可从该构建的 DerivedData 加载 framework,所以同时核对安装和实际映射的字节。不要把配置、运行路径或设备身份提交到公共源码。
每条 WDA HTTP 请求(包括 session 清理)前,CLI 使用 `lsof` 核对端口唯一 listener、`ps` 核对 PID/启动时间/执行文件,并把进程关联到指定 UUID 的 `simctl get_app_container`;随后核对安装代码与实际加载代码哈希。HTTP `/status` 的 ready、build product 与 `/wda/device/info` 的 `isSimulator` 仅作补充检查;device info 的 vendor UUID 不能当作 simulator UUID。任一检查失败均拒绝请求,不接管新 Runner、不自动恢复。
Simulator `wda-status` 包含上述本机取证以及 `/status`、`/wda/device/info` 两个只读请求;`run/eval` 的 `robot.captureScreen()` 在自己创建的一个 session 内读取尺寸与元素,PNG 仍走显式 UUID 的原生截图。坐标使用 WDA points,截图尺寸为像素。检查与 HTTP 之间不是原子绑定;静态回执、进程存活或一次 ready 均不能代替实际 UI 验证。
### 可选 iOS Wi-Fi CLI 配置
`--ios-config` 选择已经完成信任配对的 Wi-Fi 入口;不传该参数时仍保留原 go-ios / WDA 路径。该配置只用于 CLI,不改变 MCP 和 Simulator 的驱动。工具不会自动配对、生成配对记录、启动 WDA、构建或签名应用。
准备 **Python 3.11 或更新版本**,在所选 Python 环境安装可选依赖:
```sh
python -m pip install -r scripts/ios-wifi-bridge/requirements.txt
```
该入口固定依赖 [pymobiledevice3 11.32.0](https://pypi.org/project/pymobiledevice3/11.32.0/),其许可证为 **GPL-3.0-or-later**;它是使用者单独安装的可选运行依赖,不属于本仓库 Apache-2.0 许可证覆盖的第三方代码。所附 Python 文件是调用该依赖的自研适配,不包含该依赖源码或设备配对数据。默认 go-ios 路径不要求安装此 Python 依赖。
在仓库外创建私有 JSON,例如 `private-ios.json`;下列全部为占位符,必须替换成自己的已配对设备和已运行 WDA 的地址:
```json
{
"device": {
"udid": "YOUR_PAIRED_IPHONE_UDID",
"wdaUrl": "http://YOUR_WDA_HOST:8100",
"lastWifiHost": "YOUR_PAIRED_IPHONE_HOST"
},
"pythonRelative": "./YOUR_PYTHON_RUNTIME/python.exe"
}
```
`pythonRelative` 相对于该 JSON 所在目录解析;macOS/Linux 可使用自己的 Python 可执行文件路径。配对记录由使用者预先保存在所选运行用户的 `~/.pymobiledevice3/`,不得提交 JSON、配对记录或 Python 环境。命令优先复用 JSON 同目录完整的 `identity_probe.py` / `device.py` / `install_wifi.py` 脚本组;缺少任一文件时统一使用仓库随附的 `scripts/ios-wifi-bridge/`,不混用两组脚本。脚本执行仍检查真实设备 UDID,不会退回 USB 或另一台手机。UI 前身份检查仅读取配对 TCP lockdown,不创建开发者隧道、RSD 或 XCTest 服务;应用启动和安装仍通过相应受控开发接口完成。
每条设备命令都显式传相同的 `--device` 和 `--ios-config`:
```sh
node lib/cli.js devices --platform ios --device YOUR_PAIRED_IPHONE_UDID --ios-config /PRIVATE_PATH/private-ios.json
node lib/cli.js probe --platform ios --device YOUR_PAIRED_IPHONE_UDID --ios-config /PRIVATE_PATH/private-ios.json
node lib/cli.js wda-status --platform ios --device YOUR_PAIRED_IPHONE_UDID --ios-config /PRIVATE_PATH/private-ios.json
node lib/cli.js elements --platform ios --device YOUR_PAIRED_IPHONE_UDID --ios-config /PRIVATE_PATH/private-ios.json
node lib/cli.js shot ./ios-screen.png --platform ios --device YOUR_PAIRED_IPHONE_UDID --ios-config /PRIVATE_PATH/private-ios.json
```
可再传 `--wda-url http://YOUR_WDA_HOST:8100` 核对目标;它必须与私有 JSON 中配置的 HTTP(S) origin 完全相同,不接受另一个地址,也不接受凭据、路径、query 或 fragment。Wi-Fi 设备身份验证成功只证明认证传输可用,UI 操作还要求 WDA 就绪。
`wda-status` 在认证设备后仅执行一次只读 `GET /status`,输出实际 endpoint、HTTP 状态、原始响应(最多 64KiB,含 `truncated` 标记)、解析结果或错误、耗时及网络错误原因。**HTTP 200 不等于就绪**:当前只接受无 HTTP / WebDriver 协议错误且 `value.ready === true` 的响应,其余结果 `ok: false` 并返回失败退出码。大响应不重复输出完整 parsed JSON,错误文本同样限长。该命令不会创建 WDA session 或执行点击;连接错误不代表应用渲染或整个平台功能已验收失败。
批量读取 iOS 界面时,在 `run` / `eval` 中调用 `await robot.captureScreen()`,返回 `{size, elements, screenshot}`,其中截图为 `Buffer`,应通过脚本的文件接口保存。三项读取使用本次创建的同一个 WDA session,按官方路由访问 `source?format=json` 和 `screenshot`,完成或失败后清理本次 session;不会接管已有 session。单独的 `getScreenSize()`、`getElementsOnScreen()`、`getScreenshot()` 仍可分别使用。共享 session 只约束读取的会话身份,不表示三次操作发生在同一绘制帧。
应用启动和安装示例:
```sh
node lib/cli.js launch com.example.app --platform ios --device YOUR_PAIRED_IPHONE_UDID --ios-config /PRIVATE_PATH/private-ios.json
node lib/cli.js install /PRIVATE_PATH/App.ipa --pkg com.example.app --platform ios --device YOUR_PAIRED_IPHONE_UDID --ios-config /PRIVATE_PATH/private-ios.json
```
`launch` 使用显式 bundle ID,`install` 必须另传 `--pkg`。安装前读取 IPA 中唯一主 App 的 `Info.plist`,核对 bundle 与版本;安装后通过真实设备 lookup 再核对相同身份和版本,不能把设备上已有的另一应用或旧版本当作本次安装成功。Wi-Fi profile 的 `apps`、`stop`、`uninstall` 明确不支持;应用编译、签名和 WDA 部署由外部工具完成。本节描述接口和前置条件,不表示任何原始应用页面、设备型号或 GUI 交互已经通过验收。
### 一次脚本完成多个步骤
`run <script.js>` 执行脚本文件;`eval "<js>"` 执行内联脚本。两者注入 `robot`、`device`、`platform`、`sleep`、`flows`、`wv`,以及平台专用的 `adb` / `hdc`。`robot` 的接口定义见 [src/robot.ts](src/robot.ts)。
```sh
node lib/cli.js eval "return await robot.getScreenSize()"
node lib/cli.js run ./inspect.js --platform android --device ANDROID_SERIAL
```
`inspect.js` 示例(脚本体可直接 `await` / `return`):
```js
const size = await robot.getScreenSize();
const elements = await robot.getElementsOnScreen();
return { device, platform, size, elements: elements.slice(0, 10) };
```
脚本默认超时为 120 秒,可用 `--timeout 30` 调整。超时不是事务回滚,也不保证撤销已开始的设备动作。`run` / `eval` 在本机 Node.js 进程执行,不是安全沙箱;只运行你已审查、信任的脚本。
普通结果输出紧凑 JSON;`help` 输出文本,失败诊断输出到 stderr。截图命令将图片写入指定文件;自行编写脚本时,应显式保存二进制结果,不要依赖 JSON 输出携带图片。
### 原生命令与 Android WebView
常用原生命令:`apps`、`launch`、`stop`、`install`、`uninstall`、`tap`、`longpress`、`doubletap`、`tap-text`、`swipe`、`key`、`button`、`shot`、`elements`、`screen-size`、`orientation`。命令能否执行以平台支持矩阵为准;完整参数见 `help` 和 [src/cli.ts](src/cli.ts)。
WebView 只连接目标 Android 应用中已开启调试的页面,不会自动开启应用调试:
```sh
node lib/cli.js wv-pages --platform android --device ANDROID_SERIAL --pkg com.example.app
node lib/cli.js wv-outline --platform android --device ANDROID_SERIAL --pkg com.example.app
node lib/cli.js wv-style body --props color,font-size --platform android --device ANDROID_SERIAL --pkg com.example.app
node lib/cli.js wv-eval "document.title" --platform android --device ANDROID_SERIAL --pkg com.example.app
```
另有 `wv-tap-text`、`wv-shot`、`wv-net`。单命令自动连接并断开,脚本中的 `wv` 延迟到首次使用时连接。页面 JavaScript 受设备 WebView 引擎版本限制;老引擎可能不支持可选链等语法。网络记录、DOM、截图可能包含敏感信息。
### JSON 流程重放
流程是步骤数组,原生步骤复用当前平台的 Robot。下面只记录一条说明并截图:
```json
[
{ "op": "log", "note": "Capture current screen" },
{ "op": "screenshot", "saveTo": "./screen.png" }
]
```
将其保存为 `inspect.json` 后:
```sh
node lib/cli.js flow-run ./inspect.json --platform harmony --device HDC_TARGET
node lib/cli.js flow-list
node lib/cli.js flow-save inspect ./inspect.json
```
默认在失败步骤停止;`--keep-going` 会继续后续步骤,可能继续产生副作用,不等于回滚。支持步骤与参数见 [src/flows.ts](src/flows.ts),WebView 步骤与断言仅适用于 Android。
具名流程默认存于仓库 `flows/`,也可通过 `MOBILEMCP_FLOWS_DIR` 指向个人目录。个人回放、截图和现场脚本建议放入已忽略的 `ignore/`;不要把私有账号、业务内容或凭据提交到公共流程。
## MCP:另一种调用入口
CLI 使用 `lib/cli.js`;MCP 使用 **`lib/index.js`**。两者不是同一启动命令。构建后,在 MCP 客户端配置中填入本机绝对路径:
```json
{
"mcpServers": {
"mobile-cli-allinone": {
"command": "node",
"args": ["/absolute/path/to/mobile-cli-allinone/lib/index.js"],
"env": {
"MOBILEMCP_DISABLE_TELEMETRY": "1"
}
}
}
}
```
Windows 路径可写成 `D:/path/to/mobile-cli-allinone/lib/index.js`。默认使用 stdio。客户端可从 `mobile_list_available_devices` 开始,再按工具列表调用原生操作、截图、Android WebView 或流程工具;不要假定 CLI 与 MCP 的命令和驱动完全相同:MCP 没有 CLI 的 `run` / `eval` 命令,也没有独立的 HDC 文件传输、电源管理命令;原生流程可调用已支持的平台 Robot,WebView 流程仅 Android。
可选 HTTP **SSE** 模式:
```sh
node lib/index.js --listen localhost:3000
```
端点为 `http://localhost:3000/mcp`;这是 SSE transport,不是 Streamable HTTP。默认监听 localhost,当前实现仅允许一个活动 SSE 客户端。设置 `MOBILEMCP_AUTH` 后,客户端必须发送相应的 `Authorization: Bearer …`。未设置时没有认证;不要直接暴露到公网,也不要将 token 写进命令示例或仓库。
MCP 服务保留上游 PostHog 使用统计逻辑;设置 `MOBILEMCP_DISABLE_TELEMETRY=1` 可关闭,上述配置已关闭统计。
## 安全与验证范围
- 仅操作你有权控制的设备。安装/卸载、输入、点击、URL、脚本、流程和测试都可能改变应用状态、发送消息或触发交易;执行前核对设备、应用和步骤。
- 此工具不代替使用者或调用它的 agent 做授权判断。MCP 客户端应限制不受信任内容触发设备操作。
- 不提交设备截图、调试日志、令牌、签名文件或个人流程;调试工具及端口只开放给可信主机。更多见 [SECURITY.md](SECURITY.md)。
- 平台矩阵表示源码具备的接入路径。自动化测试、构建成功不等于真机验证;设备型号、OS 版本、中文输入、权限弹窗、应用兼容层、WDA 签名/tunnel 和无线连接需要在自己的环境单独验收。
开发检查:
```sh
npm run build
npm run lint
npx tsc --noEmit
npm run test:offline
```
`test:offline` 先构建,再仅运行十二个指定文件:PNG、Harmony、ADB 安装结果、原 CLI iOS 路由、WDA 错误处理、MCP 平台路由,以及 Wi-Fi CLI 身份约束、WDA 诊断、本地子进程集成、纯 lockdown 身份、IPA 安装身份与模拟器原生截图测试。它们不发现或操作真实设备;HTTP 仅连接 loopback。子进程集成测试使用本机 Python 运行合成脚本,没有 Python 时明确跳过该项。**不要在不了解测试内容时直接运行 `npm test`**:默认套件包含 Android / iOS / 模拟器测试,可能读取或改变已连接设备,部分测试在收集阶段就调用平台工具。
问题反馈:[Issues](https://github.com/xue-ding-e/mobile-cli-allinone/issues)。请附提交版本、主机系统、目标平台及脱敏复现信息,区分“源码已实现”“模拟测试通过”和“真机已验证”。
## 许可与来源
本项目基于 Mobile Next 的 mobile-mcp 开发,保留 Apache-2.0 许可证和适用的原始版权声明,详见 [LICENSE](LICENSE)。`CHANGELOG.md` 中早于本分支的版本记录属于上游历史。Android DeviceKit、mobilewright 等依赖保留各自的名称和来源。
TDQS
Scored across 35 tools
Most tools divide into clear mobile, webview, and flow groups, but run_flow's op list overlaps with many individual tools (launch_app, screenshot, webview_connect, tap_text), and there are three screenshot-related tools (mobile_take_screenshot, mobile_save_screenshot, webview_screenshot). Descriptions clarify some boundaries, but an agent could easily select a single-step run_flow or the wrong screenshot tool.
Snake_case verb_noun naming is used throughout, with clear mobile_ and webview_ prefixes plus flow verbs. Minor inconsistencies exist: the webview group lacks the mobile_ prefix, coordinate suffixes vary (click_on_screen_at_coordinates vs double_tap_on_screen vs long_press_on_screen_at_coordinates), and run_flow/save_flow/list_flows form a separate prefix family.
With 35 tools, this exceeds the 25+ threshold for 'too many' even for an all-in-one mobile/webview/flow server. Several tools could be consolidated, such as the screenshot variants and the overlap between run_flow's op set and individual action tools.
App lifecycle, device interactions, screenshots, and webview inspection are broadly covered. However, flows can be saved, listed, and run but not deleted or updated, and some run_flow operations (wait, tap_text, assert_route) have no standalone equivalents, forcing workarounds. These are notable gaps but not fatal.