内容
# 吉尔克云手机管理协议服务端
一款用于管理 **吉尔克云手机** 并通过吉尔克开放API和ADB进行安卓自动化测试的MCP(模型上下文协议)服务端。
> **非官方 / 社区项目。**
> 本项目与吉尔克公司无任何关联或背书。
高级安卓 **UI** 自动化测试(截图、UI层次、选择器、点击、文本输入、滑动)由
[`uiautomator2-mcp-server`](https://github.com/tanbro/uiautomator2-mcp-server) 处理,这是一个独立的软件包,您可以将其注册为与本服务端并行的第二个MCP服务端。两个服务端共享一个本地ADB服务端和设备序列号。单独运行geelark-mcp不是一个支持的设置:没有UI服务端,您只能通过原始坐标驱动屏幕。
> **"嘿,克劳德,创建一个新的吉尔克手机,安装TikTok,打开它,跳过引导,滚动For You feed两分钟,然后停止手机。"**
>
> `geelark-mcp` 准备手机,安装应用程序,并建立ADB连接;
> `uiautomator2-mcp-server` 处理屏幕上的交互。
---
## 功能特点
- 列出、创建、启动、停止、删除和检查吉尔克云手机。
- 从吉尔克目录安装应用;启动/停止/卸载应用。
- 启用ADB并获取规范化的ADB连接信息(默认隐藏密钥)。
- 将手机连接到本地ADB服务端,包括吉尔克的`glogin`流程。
- 通过ADB安装本地APK文件(沙盒到允许的目录,大小有限制)。
- 执行允许列出的ADB诊断/UI输入作为argv列表;原始命令需要两个标志。
- 有界的logcat、文件推送/拉取和低级坐标回退。
- 查询/取消/重试吉尔克自动化任务(仅限读取 + 生命周期)。
- 就绪和设置工具,用于向`uiautomator2-mcp-server`提供共享序列号。
- 具有每阶段结果的`prepare_phone_for_automation`工作流程。
## 项目边界
geelark-mcp处理吉尔克身份验证和请求、云手机生命周期、应用程序/文件/自动化任务管理(由文档确认)、启用ADB、检索连接信息、本地`adb connect` + `glogin`流程、设备健康检查、手机ID ↔ ADB序列号映射、本地APK安装、安全ADB命令执行和基本诊断。
外部的`uiautomator2-mcp-server`处理截图、UI层次转储、元素搜索、选择器、XPath、点击/长点击、文本输入、滚动和滑动、权限对话框处理和其他高级UI自动化测试。
两个服务端永远不会直接调用对方。它们仅通过共享的本地ADB服务端进行协作:
```
MCP主机(克劳德代码 / 克劳德桌面 / 其他)
├── geelark-mcp → 将吉尔克手机连接到本地ADB
└── uiautomator2-mcp-server → 发现并控制已经连接的序列号
```
## 安装
按照以下五个步骤依次进行。结果是两个MCP服务端注册在您的客户端中,共享一个ADB服务端。
### 步骤 1 — 前提条件
- Python **3.11+**
- **安卓平台工具** (`adb`) 在`PATH`上(或设置`GEELARK_ADB_PATH`)
- 吉尔克API Bearer令牌
- **[uv](https://docs.astral.sh/uv/)**,运行两个服务端
如果`uv --version`失败,请安装uv:
```bash
# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# Windows
winget install --id=astral-sh.uv -e
```
安装uv后,打开一个新的终端并验证两个命令:
```bash
uv --version
uvx --version
```
如果您的MCP客户端在安装期间打开,请完全退出并重新打开,以便继承更新的`PATH`。
### 步骤 2 — 检查两个服务端是否解析
`geelark-mcp` 和 `uiautomator2-mcp-server` 是 **独立的软件包**,`uvx` 在需要时将每个软件包加载到其自己的隔离环境中。无需安装 — 您的MCP客户端将在步骤 4 中直接调用`uvx`。
运行两者一次以预热缓存并确认它们已解析:
```bash
uvx geelark-mcp --version
uvx --from uiautomator2-mcp-server u2mcp --help
```
贡献者如果要开发代码,应遵循[开发](#开发)部分。
### 步骤 3 — 启动共享的ADB服务端
两个服务端必须与同一个ADB服务端通信,否则geelark-mcp生成的序列号对UI服务端不可见。启动一次:
```bash
adb start-server
```
这会绑定`127.0.0.1:5037`,即步骤 4 中使用的套接字。守护进程然后会运行直到您重启或运行`adb kill-server`,因此这是一个**每次启动**,而不是**每次会话** — 重新连接MCP服务端不需要重复。
> 不要写`adb -L tcp:127.0.0.1:5037 start-server`。`-L`标志将套接字标记为远程,adb拒绝为其生成守护进程:
> `无法在远程主机上启动服务器`。同样,环境中设置`ADB_SERVER_SOCKET`也是如此 — 这正是geelark-mcp所做的,因此它无法为您启动守护进程。某些东西必须首先启动它,而这一步骤就是。
### 步骤 4 — 在MCP客户端中注册两个服务端
两个服务端被注册为两个独立的条目。两者必须携带来自步骤 3 的相同ADB套接字:`GEELARK_ADB_SERVER_SOCKET`用于geelark-mcp,`ADB_SERVER_SOCKET`用于uiautomator2。
#### 选项 A — 编辑配置文件(在每个客户端中有效)
复制整个`mcpServers`对象从
[examples/mcp-config.json](examples/mcp-config.json) — 它已经包含两个服务端与匹配的套接字 — 到您的客户端配置文件中:
| 客户端 | 文件 | `mcpServers`放置位置 |
| --- | --- | --- |
| 克劳德代码(VS Code扩展或终端),所有项目 | `~/.claude.json` | 在顶级 |
| 克劳德代码,一个项目 | `<project>/.mcp.json` | 在顶级 |
| 克劳德桌面 | `claude_desktop_config.json` | 在顶级 |
替换每个`REPLACE_WITH_...`占位符,然后重新加载客户端(对于克劳德桌面,重启应用程序)并检查`/mcp`。
永远不要在共享的`.mcp.json`中提交真实的凭证 — 而是引用它们:
```json
"env": {
"GEELARK_BEARER_TOKEN": "${GEELARK_BEARER_TOKEN}"
}
```
`~/.claude.json`和`claude_desktop_config.json`以纯文本形式存储`env`值。请保持它们私有,如果您不想在那里存储秘密,可以使用OS环境变量。
#### 选项 B — `claude` CLI
仅当独立的克劳德代码CLI已安装并在您的`PATH`上时。**VS Code扩展不提供它** — 使用`claude --version`检查,首先如果失败则使用选项A。
```bash
claude mcp add --transport stdio \
--env GEELARK_BEARER_TOKEN=your_token \
--env GEELARK_ADB_SERVER_SOCKET=tcp:127.0.0.1:5037 \
geelark -- uvx geelark-mcp serve
claude mcp add --transport stdio \
--env ADB_SERVER_SOCKET=tcp:127.0.0.1:5037 \
uiautomator2 -- uvx --from uiautomator2-mcp-server u2mcp stdio
```
`--`之后的所有内容都是启动命令。
作用域默认为`local`(对当前项目私有)。为每个项目添加 `--scope user`,或使用 `--scope project` 通过提交的`.mcp.json`共享。
> 在Windows PowerShell中,上面的尾随`\`行延续是一个语法错误。将每个命令放在一行上,或使用反引号 `` ` ``代替。
### 步骤 5 — 验证
**重启客户端**并检查`/mcp`:`geelark`和`uiautomator2`都应该已连接。如果在克劳德或VS Code打开时安装了uv,请在重新打开它之前关闭其所有进程;重新连接MCP服务端不会刷新`PATH`。然后确认两个服务端都同意ADB环境:
```
verify_shared_adb_environment()
```
报告的`adb_server_socket`必须与步骤 3 中的套接字匹配。有关其他选项,请参见[配置参考](#配置参考),如果服务端启动失败,请参见[故障排除](#故障排除)。
## 配置参考
通过MCP客户端将配置传递给服务端作为环境变量。`GEELARK_BEARER_TOKEN`是必需的;仅支持Bearer身份验证。
| 变量 | 默认值 | 目的 |
| --- | --- | --- |
| `GEELARK_BEARER_TOKEN` | 必需 | 吉尔克Bearer令牌;视为秘密 |
| `GEELARK_BASE_URL` | `https://openapi.geelark.com` | 吉尔克API主机根 |
| `GEELARK_REQUEST_TIMEOUT` | `30` | API读写/池超时,单位:秒 |
| `GEELARK_CONNECT_TIMEOUT` | `10` | API连接超时,单位:秒 |
| `GEELARK_MAX_RETRIES` | `3` | 合格API调用的最大重试次数(`0`–`10`) |
| `GEELARK_LOG_LEVEL` | `INFO` | Python日志级别 |
| `GEELARK_ADB_PATH` | `adb` | ADB可执行文件名称或绝对路径 |
| `GEELARK_ADB_SERVER_SOCKET` | 未设置 | 共享ADB套接字,例如`tcp:127.0.0.1:5037` |
| `GEELARK_ADB_CONNECT_TIMEOUT` | `30` | ADB连接/glogin超时,单位:秒 |
| `GEELARK_ADB_COMMAND_TIMEOUT` | `60` | 默认ADB命令超时,单位:秒 |
| `GEELARK_ALLOW_DANGEROUS_ADB` | `false` | 启用每次调用原始ADB选择 |
| `GEELARK_ALLOWED_APK_ROOT` | 未设置 | 可以安装本地APK的目录 |
| `GEELARK_MAX_APK_SIZE_MB` | `500` | 本地APK的最大大小 |
| `GEELARK_STOP_MANAGED_PHONES_ON_EXIT` | `false` | 在关闭时停止此服务端启动的手机 |
默认情况下,机密不会被工具输出显示,并且会从日志中删除。显式返回机密的选项应仅在MCP客户端及其历史记录受信任时使用。
## 手动运行服务端
MCP客户端通常为您启动服务端;仅在调试或非stdio传输时手动运行。
```bash
geelark-mcp serve
# 或
python -m geelark_mcp serve
```
可流式HTTP(仅限本地;请参见安全说明):
```bash
geelark-mcp serve --transport streamable-http --host 127.0.0.1 --port 8000
```
> 默认情况下,可流式HTTP绑定到`127.0.0.1`,并且**从不**绑定到`0.0.0.0`。
> 公共部署需要身份验证、TLS、反向代理、源验证和网络访问控制。初始版本针对stdio。
## ADB连接的工作原理
内部连接流程为:
```text
吉尔克 /adb/setStatus
-> 吉尔克 /adb/getData
-> adb connect host:port
-> adb -s host:port shell glogin <connection-code>
-> adb -s host:port get-state
```
连接代码被视为秘密,不由组合工作流返回。`adb_disconnect(phone_id="...")`仅断开由服务端记录的会话;它从不停止共享的ADB服务端。仅当`GEELARK_STOP_MANAGED_PHONES_ON_EXIT=true`时,云手机在关闭时停止。
## 示例端到端工作流程
1. `prepare_phone_for_automation(phone_id="...")` — 启动手机,启用ADB,连接,运行`glogin`,验证设备在线并返回ADB序列号(`host:port`)以及每个阶段的结果。
2. 使用`verify_shared_adb_environment(target_serial="host:port")`确认序列号。
3. 在`uiautomator2-mcp-server`中,选择确切的序列号并使用其UI工具(截图、转储层次、点击、设置文本、滑动、...)。
示例工具调用(参数为JSON):
```json
{ "name": "list_phones", "arguments": { "page": 1, "page_size": 20 } }
```
## 多设备行为
当连接多个设备时,geelark-mcp从不假设第一个设备。命令工具通过`adb_connect`创建的手机ID ↔ 序列号映射来解析序列号。准备工具在多个设备在线时发出警告。始终将确切的序列号传递给外部UI服务端,而不是依赖自动选择。
## 安全考虑
机密不会被工具输出显示,并且会从日志中删除。ADB在没有`shell=True`的情况下运行;原始命令需要两个明确的选择。本地APK安装仅限于`GEELARK_ALLOWED_APK_ROOT`。
## 故障排除
### 启动时的配置错误
- `GEELARK_BEARER_TOKEN不能为空`:通过MCP客户端配置或进程环境传递令牌。
- `GEELARK_BASE_URL必须使用HTTPS` / `必须是主机根而非端点路径`:使用`https://openapi.geelark.com`而非端点路径。
- `ADB可执行文件... 未找到`:安装安卓平台工具或设置`GEELARK_ADB_PATH`。
- `GEELARK_ALLOWED_APK_ROOT... 不存在`:指向现有目录。
- `GEELARK_ADB_SERVER_SOCKET必须类似于'tcp:<host>:<port>'或'unix:<path>'`:修复套接字格式。
- `无法在远程主机上启动服务端` / `无法连接到tcp:127.0.0.1:5037的守护进程`:没有ADB守护进程正在运行,并且`GEELARK_ADB_SERVER_SOCKET`阻止adb启动一个。运行`adb start-server`(无`-L`标志)并重试。
### 工具返回`ok: false`
使用`error.kind`识别失败:
| 类型 | 含义 | 典型修复 |
| --- | --- | --- |
| `auth` | Bearer令牌被拒绝 | 检查`GEELARK_BEARER_TOKEN` |
| `validation` | 参数错误 | 读取消息并修复输入 |
| `not_found` | 手机、应用、任务或会话丢失 | 验证ID;首先连接 |
| `rate_limit` | 请求过多 | 在重试前等待 |
| `timeout` | 请求的状态未及时达到 | 在重试前检查当前状态 |
| `unknown_outcome` | 变异调用可能已应用 | 在重试前验证状态 |
| `security` | 命令在安全ADB允许列表之外 | 使用专用工具或显式启用原始ADB |
| `adb_error` | 本地ADB失败 | 检查`stderr`或`data.stages` |
### `adb_connect`失败
检查`data.stages`:
- `wait_running`:增加`timeout_seconds`或在吉尔克中检查手机。
- `wait_adb`:确认手机型号支持ADB(错误`49002`表示不支持)。
- `adb_connect`:检查网络路径和到`ip:port`的防火墙访问。
- `adb_health_check`:如果设备连接但未达到`device`状态,请重试;这通常是暂时的`glogin`问题。
如果UI服务端看不到设备,请运行`adb_devices`和`verify_shared_adb_environment`。确认两个服务端使用相同的ADB套接字,并且在连接多个设备时始终选择确切的序列号。
日志输出到stderr,因为stdout保留用于MCP协议。设置`GEELARK_LOG_LEVEL=DEBUG`以获取更多详细信息。
## 开发
```bash
git clone https://github.com/techinz/geelark-mcp
cd geelark-mcp
uv sync --dev
uv run ruff check .
uv run ruff format --check .
uv run mypy src
uv run pytest
```
参见 [CONTRIBUTING.md](CONTRIBUTING.md)。
## 许可证
[MIT](LICENSE).
## 链接
- 吉尔克开放API文档:https://github.com/GeeLark/geelark-openapi
- 模型上下文协议:https://modelcontextprotocol.io
- Python MCP SDK / FastMCP:https://github.com/modelcontextprotocol/python-sdk
- 外部UI自动化:https://github.com/tanbro/uiautomator2-mcp-server