Skip to main content

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-mcp provisions the phone, installs the app, and establishes ADB; uiautomator2-mcp-server handles 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 glogin flow.
  • 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_automation workflow 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) on PATH (or set GEELARK_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 -L flag marks the socket as remote, and adb refuses to spawn a daemon for one: cannot start server on remote host. The same applies to ADB_SERVER_SOCKET being 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 (010)
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.1 by default and is never 0.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

  1. prepare_phone_for_automation(phone_id="...") — starts the phone, enables ADB, connects, runs glogin, verifies the device is online and returns the ADB serial (host:port) plus per-stage results.
  2. Confirm the serial with verify_shared_adb_environment(target_serial="host:port").
  3. 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: use https://openapi.geelark.com without an endpoint path.
  • ADB executable ... was not found: install Android Platform Tools or set GEELARK_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 and GEELARK_ADB_SERVER_SOCKET prevents adb from starting one. Run adb start-server (no -L flag) 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: increase timeout_seconds or check the phone in GeeLark.
  • wait_adb: confirm that the phone model supports ADB (error 49002 means unsupported).
  • adb_connect: check the network path and firewall access to ip:port.
  • adb_health_check: retry if the device connected but did not reach device state; this is commonly a transient glogin issue.

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

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

geelark_mcp-0.1.0.tar.gz (45.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

geelark_mcp-0.1.0-py3-none-any.whl (60.7 kB view details)

Uploaded Python 3

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

Hashes for geelark_mcp-0.1.0.tar.gz
Algorithm Hash digest
SHA256 e8abe004ef8bf9358116ab7470c826b6b5104690f4b43a8688573294b432b0b0
MD5 8a0162666f741bb9e9685fae2cd0ce25
BLAKE2b-256 1bf7e151ea724560b58c5fea0787e5344a77ac765f3a81b32e60ee15d473403b

See more details on using hashes here.

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

Hashes for geelark_mcp-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 340d06dc40771767877001e6784bf763909790304ef09a8801958ea219cbc35b
MD5 2d60473855b905de93bfc3d5f96e6c8e
BLAKE2b-256 edfad3061f7c34191be8d5e73afb26c0ad59400dbf52c38601b78949c5607560

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page