geelark-mcp
An MCP (Model Context Protocol) server for managing GeeLark Cloud Phones through the official GeeLark OpenAPI and preparing running devices for Android automation over ADB.
Unofficial / community project. This project is not affiliated with or endorsed by GeeLark.
High-level Android UI automation (screenshots, UI hierarchy, selectors,
clicks, text input, swipes) is handled by
uiautomator2-mcp-server, a
separate package you register as a second MCP server alongside this one. The two
share a local ADB server and device serial. Running geelark-mcp on its own is not
a supported setup: without the UI server you can only drive the screen by raw
coordinates.
"Hey Claude, create a fresh GeeLark phone, install TikTok, open it, skip onboarding, scroll the For You feed for two minutes and stop the phone."
geelark-mcpprovisions the phone, installs the app, and establishes ADB;uiautomator2-mcp-serverhandles the on-screen interaction.
Features
- List, create, start, stop, delete and inspect GeeLark cloud phones.
- Install apps from the GeeLark catalog; start/stop/uninstall apps.
- Enable ADB and retrieve normalized ADB connection info (secret withheld by default).
- Connect a phone to the local ADB server, including the GeeLark
gloginflow. - Install local APKs over ADB (sandboxed to an allowed directory, size-limited).
- Execute allowlisted ADB diagnostics/UI input as argv lists; raw commands require two flags.
- Bounded logcat, file push/pull, and low-level coordinate fallbacks.
- Query / cancel / retry GeeLark automation tasks (read + lifecycle only).
- Readiness and setup tools to hand a shared serial to
uiautomator2-mcp-server. - A one-shot
prepare_phone_for_automationworkflow with per-stage results.
Project boundaries
geelark-mcp handles GeeLark authentication and requests, cloud phone lifecycle,
application/file/automation-task management (as confirmed by the docs), enabling
ADB, retrieving connection info, the local adb connect + glogin flow, device
health checks, the phone ID ↔ ADB serial mapping, local APK installation, safe ADB
command execution and basic diagnostics.
The external uiautomator2-mcp-server handles screenshots, UI hierarchy dumps,
element search, selectors, XPath, clicks/long-clicks, text entry, scrolling and
swiping, permission-dialog handling and other high-level UI automation.
The two servers never call each other directly. They cooperate only through the shared local ADB server:
MCP host (Claude Code / Claude Desktop / other)
├── geelark-mcp → connects the GeeLark phone to local ADB
└── uiautomator2-mcp-server → discovers & controls the already-connected serial
Installation
Follow the five steps below in order. The result is two MCP servers registered in your client, sharing one ADB server.
Step 1 — Prerequisites
- Python 3.11+
- Android Platform Tools (
adb) onPATH(or setGEELARK_ADB_PATH) - GeeLark API Bearer token
- uv, which runs both servers
Install uv if uv --version fails:
# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# Windows
winget install --id=astral-sh.uv -e
After installing uv, open a new terminal and verify both commands:
uv --version
uvx --version
If your MCP client was open during installation, fully quit and reopen it so it
inherits the updated PATH.
Step 2 — Check that both servers resolve
geelark-mcp and uiautomator2-mcp-server are independent packages, and
uvx fetches each into its own isolated environment on demand. There is nothing
to install — your MCP client invokes uvx directly in step 4.
Run both once to warm the cache and confirm they resolve:
uvx geelark-mcp --version
uvx --from uiautomator2-mcp-server u2mcp --help
Contributors working on the code should follow Development instead.
Step 3 — Start a shared ADB server
Both servers must talk to the same ADB server, otherwise the serial produced by geelark-mcp is invisible to the UI server. Start it once:
adb start-server
This binds 127.0.0.1:5037, the socket used in step 4. The daemon then stays up
until you reboot or run adb kill-server, so this is once per boot, not once
per session — reconnecting the MCP servers does not need it repeated.
Do not write
adb -L tcp:127.0.0.1:5037 start-server. The-Lflag marks the socket as remote, and adb refuses to spawn a daemon for one:cannot start server on remote host. The same applies toADB_SERVER_SOCKETbeing set in the environment — which is exactly what geelark-mcp does, so it cannot bootstrap the daemon for you. Something must start it first, and that is this step.
Step 4 — Register both servers in your MCP client
The two servers are registered as two independent entries. Both must carry the
same ADB socket from step 3: GEELARK_ADB_SERVER_SOCKET for geelark-mcp,
ADB_SERVER_SOCKET for uiautomator2.
Option A — edit the configuration file (works in every client)
Copy the whole mcpServers object from
examples/mcp-config.json — it already contains both
servers with a matching socket — into your client's configuration file:
| Client | File | mcpServers goes |
|---|---|---|
| Claude Code (VS Code extension or terminal), all projects | ~/.claude.json |
at the top level |
| Claude Code, one project | <project>/.mcp.json |
at the top level |
| Claude Desktop | claude_desktop_config.json |
at the top level |
Replace every REPLACE_WITH_... placeholder, then reload the client (restart the
app for Claude Desktop) and check /mcp.
Never commit real credentials in a shared .mcp.json — reference them instead:
"env": {
"GEELARK_BEARER_TOKEN": "${GEELARK_BEARER_TOKEN}"
}
~/.claude.json and claude_desktop_config.json store env values as
plaintext. Keep them private, and prefer OS environment variables if you would
rather not store secrets there at all.
Option B — the claude CLI
Only if the standalone Claude Code CLI is installed and on your PATH. The VS
Code extension does not provide it — check with claude --version first, and
use Option A if that fails.
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
Everything after -- is the launch command.
Scope defaults to local (private to the current project). Add --scope user
for every project, or --scope project to share through a committed .mcp.json.
On Windows PowerShell the trailing
\line continuations above are a syntax error. Put each command on one line, or use a backtick`instead.
Step 5 — Verify
Restart the client and check /mcp: both geelark and uiautomator2 should
be connected. If uv was installed while Claude or VS Code was open, close all of
its processes before reopening it; reconnecting the MCP server alone does not
refresh PATH. Then confirm both servers agree on the ADB environment:
verify_shared_adb_environment()
The reported adb_server_socket must match the socket from step 3. See
Configuration reference for the remaining options and
Troubleshooting if a server fails to start.
Configuration reference
Pass configuration to the server as environment variables through your MCP
client. GEELARK_BEARER_TOKEN is required; only Bearer authentication is
supported.
| Variable | Default | Purpose |
|---|---|---|
GEELARK_BEARER_TOKEN |
required | GeeLark Bearer token; treat as a secret |
GEELARK_BASE_URL |
https://openapi.geelark.com |
GeeLark API host root |
GEELARK_REQUEST_TIMEOUT |
30 |
API read/write/pool timeout in seconds |
GEELARK_CONNECT_TIMEOUT |
10 |
API connection timeout in seconds |
GEELARK_MAX_RETRIES |
3 |
Maximum retries for eligible API calls (0–10) |
GEELARK_LOG_LEVEL |
INFO |
Python log level |
GEELARK_ADB_PATH |
adb |
ADB executable name or absolute path |
GEELARK_ADB_SERVER_SOCKET |
unset | Shared ADB socket, e.g. tcp:127.0.0.1:5037 |
GEELARK_ADB_CONNECT_TIMEOUT |
30 |
ADB connect/glogin timeout in seconds |
GEELARK_ADB_COMMAND_TIMEOUT |
60 |
Default ADB command timeout in seconds |
GEELARK_ALLOW_DANGEROUS_ADB |
false |
Enables per-call raw ADB opt-in |
GEELARK_ALLOWED_APK_ROOT |
unset | Directory from which local APKs may be installed |
GEELARK_MAX_APK_SIZE_MB |
500 |
Maximum local APK size |
GEELARK_STOP_MANAGED_PHONES_ON_EXIT |
false |
Stops phones started by this server on shutdown |
Secrets are withheld from tool output by default and redacted from logs. Options that explicitly return a secret should be used only when the MCP client and its history are trusted.
Running the server manually
The MCP client normally launches the server for you; run it by hand only for debugging or for a non-stdio transport.
geelark-mcp serve
# or
python -m geelark_mcp serve
Streamable HTTP (local only; see security note):
geelark-mcp serve --transport streamable-http --host 127.0.0.1 --port 8000
Streamable HTTP binds to
127.0.0.1by default and is never0.0.0.0. Public deployment requires authentication, TLS, a reverse proxy, origin validation and network access controls. The initial release targets stdio.
How the ADB connection works
Internally, the connection flow is:
GeeLark /adb/setStatus
-> GeeLark /adb/getData
-> adb connect host:port
-> adb -s host:port shell glogin <connection-code>
-> adb -s host:port get-state
The connection code is treated as a secret and is not returned by the combined
workflow. adb_disconnect(phone_id="...") disconnects only a session recorded
by this server; it never stops the shared ADB server. Cloud phones are stopped on
shutdown only when GEELARK_STOP_MANAGED_PHONES_ON_EXIT=true.
Example end-to-end workflow
prepare_phone_for_automation(phone_id="...")— starts the phone, enables ADB, connects, runsglogin, verifies the device is online and returns the ADB serial (host:port) plus per-stage results.- Confirm the serial with
verify_shared_adb_environment(target_serial="host:port"). - In
uiautomator2-mcp-server, select that exact serial and use its UI tools (screenshot, dump hierarchy, click, set text, swipe, …).
Example tool call (arguments as JSON):
{ "name": "list_phones", "arguments": { "page": 1, "page_size": 20 } }
Multi-device behavior
When more than one device is connected, geelark-mcp never assumes the first one.
Command tools resolve the serial from the phone ID ↔ serial mapping created by
adb_connect. Readiness tools warn when multiple devices are online. Always pass
the exact serial to the external UI server rather than relying on auto-selection.
Security considerations
Secrets are withheld from tool output and redacted from logs. ADB runs without
shell=True; raw commands require two explicit opt-ins. Local APK installation
is limited to GEELARK_ALLOWED_APK_ROOT.
Troubleshooting
Configuration errors on startup
GEELARK_BEARER_TOKEN must not be empty: pass the token through the MCP client configuration or process environment.GEELARK_BASE_URL must use HTTPS/must be a host root without an endpoint path: usehttps://openapi.geelark.comwithout an endpoint path.ADB executable ... was not found: install Android Platform Tools or setGEELARK_ADB_PATH.GEELARK_ALLOWED_APK_ROOT ... does not exist: point it at an existing directory.GEELARK_ADB_SERVER_SOCKET must look like 'tcp:<host>:<port>' or 'unix:<path>': fix the socket format.cannot start server on remote host/cannot connect to daemon at tcp:127.0.0.1:5037: no ADB daemon is running andGEELARK_ADB_SERVER_SOCKETprevents adb from starting one. Runadb start-server(no-Lflag) and retry.
Tool returns ok: false
Use error.kind to identify the failure:
| kind | meaning | typical fix |
|---|---|---|
auth |
Bearer token rejected | check GEELARK_BEARER_TOKEN |
validation |
bad arguments | read the message and fix the inputs |
not_found |
phone, app, task or session missing | verify the ID; connect first |
rate_limit |
too many requests | back off before retrying |
timeout |
requested state was not reached in time | inspect current state before retrying |
unknown_outcome |
mutating call may have applied | verify state before retrying |
security |
command is outside the safe ADB allowlist | use a dedicated tool or explicitly enable raw ADB |
adb_error |
local ADB failed | inspect stderr or data.stages |
adb_connect fails
Inspect data.stages:
wait_running: increasetimeout_secondsor check the phone in GeeLark.wait_adb: confirm that the phone model supports ADB (error49002means unsupported).adb_connect: check the network path and firewall access toip:port.adb_health_check: retry if the device connected but did not reachdevicestate; this is commonly a transientgloginissue.
If the UI server cannot see the device, run adb_devices and
verify_shared_adb_environment. Confirm both servers use the same ADB socket and
always select the exact serial when multiple devices are connected.
Logs go to stderr because stdout is reserved for the MCP protocol. Set
GEELARK_LOG_LEVEL=DEBUG for more detail.
Development
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
See CONTRIBUTING.md.
License
MIT.
Links
- GeeLark OpenAPI docs: https://github.com/GeeLark/geelark-openapi
- Model Context Protocol: https://modelcontextprotocol.io
- Python MCP SDK / FastMCP: https://github.com/modelcontextprotocol/python-sdk
- External UI automation: https://github.com/tanbro/uiautomator2-mcp-server
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file geelark_mcp-0.1.0.tar.gz.
File metadata
- Download URL: geelark_mcp-0.1.0.tar.gz
- Upload date:
- Size: 45.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.30 {"installer":{"name":"uv","version":"0.11.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e8abe004ef8bf9358116ab7470c826b6b5104690f4b43a8688573294b432b0b0
|
|
| MD5 |
8a0162666f741bb9e9685fae2cd0ce25
|
|
| BLAKE2b-256 |
1bf7e151ea724560b58c5fea0787e5344a77ac765f3a81b32e60ee15d473403b
|
File details
Details for the file geelark_mcp-0.1.0-py3-none-any.whl.
File metadata
- Download URL: geelark_mcp-0.1.0-py3-none-any.whl
- Upload date:
- Size: 60.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.30 {"installer":{"name":"uv","version":"0.11.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
340d06dc40771767877001e6784bf763909790304ef09a8801958ea219cbc35b
|
|
| MD5 |
2d60473855b905de93bfc3d5f96e6c8e
|
|
| BLAKE2b-256 |
edfad3061f7c34191be8d5e73afb26c0ad59400dbf52c38601b78949c5607560
|