uitree-local
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@uitree-local take a screenshot and describe the current screen"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
uitree-local — 本地 Uitree Portal 工具链
为精简为本地-only 的 Uitree Portal APK(v0.7.24)配套的 MCP server、CLI agent 与 skills。全部流量走本机(HTTP 8080 / WebSocket 8081),无任何云端依赖。
MCP server 基于 mcp 2.x SDK,实现 2026-07-28 最新协议: 无状态(无 handshake / Session-Id)、
server/discover服务发现、JSON Schema 2020-12。27 个工具覆盖:UI 树读取、截图、点按/滑动/按键、输入、剪贴板、App 管理、文件、 APK 安装、防休眠。
agent/提供自然语言任务循环(OpenAI 兼容 LLM,可选 vision),与 MCP 共用同一套工具。
官方
api.uitree.ai/v1/mcp是托管闭源服务(dr_sk_key 计费)。 本项目是自建替代:MCP server + skills + agent 全部在本地跑,直连 Portal APK 的本地 API。
目录结构
mcp-server/
├── pyproject.toml # mcp>=2.0.0, websocket-client, httpx; pytest dev
├── src/uitree_mcp/
│ ├── portal_client.py # Portal HTTP/WS 客户端(token 解析 + adb forward 自动)
│ ├── tools.py # 27 个工具定义(MCP server 与 agent 共用)
│ ├── server.py # MCP server(stdio / streamable-http)
│ └── agent.py # CLI agent(LLM 循环 + vision 截图)
├── skills/uitree/SKILL.md # opencode/anthropic 风格 skill
├── agent/ # agent 说明与示例
└── tests/ # 17 个单测(假 Portal + 假 LLM,无需真机)Related MCP server: Phone MCP
安装 & 运行
前置:adb devices 可见设备(如 emulator-5554);Portal APK 已安装并启用无障碍服务;
token 自动解析(显式 > UITREE_TOKEN > adb content provider),端口自动 forward。
cd mcp-server
uv sync
# 1) MCP server(stdio —— 供 Claude Desktop / opencode 等客户端接入)
uv run uitree-mcp
# 客户端配置示例(claude mcp add / opencode mcp add):
# uitree-local: {"type": "stdio", "command": "uv", "args": ["run", "--project", "/path/to/mcp-server", "uitree-mcp"]}
# 2) MCP server(streamable-http,2026-07-28 无状态)
uv run uitree-mcp --transport streamable-http --port 8083
# 客户端连接: http://127.0.0.1:8083/mcp
# 3) CLI agent(自然语言任务;LLM 用 OpenAI 兼容端点,Ollama 也可)
UITREE_LLM_BASE=https://api.openai.com/v1 UITREE_LLM_MODEL=gpt-4o \
UITREE_LLM_API_KEY=sk-... \
uv run uitree-agent "打开设置,滑动到存储,截图汇报占用情况"
# Ollama 本地:
UITREE_LLM_BASE=http://localhost:11434/v1 UITREE_LLM_MODEL=llama3.2-vision \
UITREE_LLM_VISION=1 uv run uitree-agent "看下当前屏幕有什么"验证
uv run pytest tests/ # 17 个单测(无需设备)
curl -s http://127.0.0.1:8080/ping -H "Authorization: Bearer $KEY" # → pong
uv run uitree-mcp --transport streamable-http --port 8083 & # 手工联调关键设计
单一工具源:
tools.py的 ToolDef 同时驱动 MCP server(server.py把 schema 逐字映射为 wire inputSchema)与 agent(进程内直调,零 MCP 往返)。token 安全:token 不出本机;
uitree-mcp也可用--token显式传入,避免 adb shell。WS 专有能力:
install_apk、set_keep_awake走 WebSocket JSON-RPC({id, method, params})。协议最新:mcp 2.x 为 2026-07-28 规范重写的 SDK(
MCPServer取代FastMCP), 自动处理server/discover、响应缓存、无状态 HTTP。
Available Tools
30 toolsdelete_fileC
Deletes a file on the device.
Inputs: path (required).
get_clipboardB
Reads the current clipboard content.
Inputs: no named parameters.
get_element_treeB
Returns only the accessibility element tree of the current screen as JSON.
Inputs: filter.
get_keep_awake_statusA
Returns whether screen keep-awake is currently active.
Inputs: no named parameters.
get_phone_stateA
Returns phone state: current app, screen on/off, battery, connectivity.
Inputs: no named parameters.
get_screenshotA
Takes a screenshot of the device screen and returns it as an image. Use this for visual verification of UI before/after actions.
Inputs: hide_overlay.
get_screen_stateA
Returns the current UI accessibility tree (text, class names, bounds) plus phone state and screen dimensions. Call this first to understand what is on screen, then use tap / swipe / keyboard_input with coordinates taken from the returned bounds.
Inputs: filter.
get_versionA
Returns the installed Portal app version.
Inputs: no named parameters.
install_apkA
Installs one or more APKs from URLs on the device (WebSocket required). Automatically accepts the install confirmation via the Portal.
Inputs: urls (required), hide_overlay.
is_overlay_visibleA
Returns whether the Portal overlay is currently visible.
Inputs: no named parameters.
keyboard_clearC
Clears the currently focused text field.
Inputs: verify, verify_poll_ms, verify_timeout_ms.
keyboard_inputA
Types text into the currently focused field using the Portal keyboard bridge. Set clear=false to append instead of replacing the field content.
Inputs: text (required), clear, verify, verify_poll_ms, +1 more.
keyboard_keyB
Sends a key press. Use named keys: back, home, app_switch, menu, enter, del, tab, space, escape, search, volume_up, volume_down, arrow_up/down/left/right, or a raw Android keycode integer.
Inputs: key (required), verify, verify_poll_ms, verify_timeout_ms.
launch_appB
Launches an app by package name (and optional activity). Use list_installed_apps to find package names.
Inputs: package (required), verify, activity, verify_poll_ms, +2 more.
list_filesB
Lists files in a directory on the device.
Inputs: path (required).
list_installed_appsA
Lists installed packages. Returns a large list; grep it for the app you want.
Inputs: no named parameters.
long_pressA
Long-presses at (x, y) for duration_ms (default 600). Opens context menus, selects text, or grabs an icon before dragging. For element targets with humanized random points use long_press_element.
Inputs: x (required), y (required), verify, duration_ms, +2 more.
long_press_elementA
Long-presses an element identified by bounds (random point inside the bounds, edge margin excluded). For e.g. icon long-press menus.
Inputs: bounds (required), margin, verify, duration_ms, +2 more.
open_deep_linkB
Opens a deep link / URL (or intent). Use for URLs, market links, custom schemes.
Inputs: deep_link (required), verify, package, verify_poll_ms, +1 more.
pingB
Checks whether the Portal device API is reachable and responding.
Inputs: no named parameters.
press_global_actionB
Performs a system-level action. Valid actions: back, home, recents, notifications, quick_settings, power_dialog, toggle_split_screen, lock_screen, take_screenshot, headphone_button, dock_and_hold. Uses Android GLOBAL_ACTION_* semantics, requires the Portal accessibility service to be enabled.
Inputs: action (required).
read_fileA
Reads a file from the device and returns its content base64-encoded as data URI. Decode it if you need the raw bytes.
Inputs: path (required).
set_clipboardC
Writes text to the device clipboard.
Inputs: text (required), verify, verify_poll_ms, verify_timeout_ms.
set_keep_awakeB
Prevents the screen from sleeping while the connection is active (WebSocket required).
Inputs: enabled (required).
set_overlay_offsetC
Adjusts the Portal floating-offset (only meaningful when the overlay is enabled).
Inputs: offset (required).
stop_appC
Force-stops an app by package name.
Inputs: package (required), verify, verify_poll_ms, verify_timeout_ms.
swipeA
Swipes (or drags) from one point to another over the given duration. A slow swipe (>400ms) reads as a drag in most apps.
Inputs: end_x (required), end_y (required), start_x (required), start_y (required), +4 more.
tapA
Taps at the given screen coordinates (pixels, 0,0 = top-left). Read coordinates from get_screen_state bounds. Prefer tap_element when you have a node's bounds: it picks the point randomly inside the element.
Inputs: x (required), y (required), verify, verify_poll_ms, +1 more.
tap_elementA
Taps an element identified by its accessibility bounds. The tap point is chosen randomly inside the bounds after excluding margin pixels on each edge (center fallback for small elements), so repeated taps never land on identical pixels. Get bounds from get_screen_state.
Inputs: bounds (required), margin, verify, verify_poll_ms, +1 more.
write_fileB
Writes base64-encoded bytes to a file on the device (max ~4MB decoded).
Inputs: path (required), data_b64 (required).
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 30 tools
Several tools overlap: get_screen_state already includes element tree and phone state, making get_element_tree and get_phone_state potentially confusing; keyboard_key and press_global_action both handle back/home; tap vs tap_element and long_press vs long_press_element split the same action by target type. Descriptions clarify intended use, but an agent still faces multiple plausible choices.
Names are consistently snake_case and mostly follow verb_noun or noun_verb patterns (get_screen_state, launch_app, tap_element). Minor deviations exist: keyboard_clear and keyboard_key put the noun first, and bare verbs tap/swipe/ping lack a noun. Overall readable and predictable.
30 tools is high for a device-automation MCP and exceeds the typical 3-15 well-scoped range; several getters are redundant because get_screen_state already bundles element tree and phone state. This inflates surface area and increases selection cost.
The surface covers core device control well: screen inspection, taps/swipes, keyboard, global actions, apps, files, clipboard, overlay, and keep-awake. Minor gaps remain (e.g., pinch/zoom or multi-touch gestures, wait-for-idle), but agents can work around them with existing swipe/tap primitives.
Maintenance
Related MCP Connectors
Drive real devices from your AI Coding tool. Embed a client SDK (Unity, Godot, Flutter, iOS/macOS, Android, React Native, Web) in your app, then capture screenshots, traverse the UI tree, inject taps and key events, and run automated test tasks on the physical device over a secure relay.
remote debug iOS/Android/Unity/Godot/Flutter/RN/Web on real-device.ui-tree/screenshots/taps,tests.
Melaya is a remote MCP server. It gives an assistant hands on your own Android phone and browser: it reads the screen through the accessibility tree, then taps, types and navigates inside the apps and sites you allow-list, with no per-app API. It also builds, schedules and runs agent pipelines across 6k+ connected tools. OAuth 2.1, nothing to install.
Securely control computers you explicitly pair through files, terminals, processes, screenshots, desktop UI/input, clipboard, browser automation, diagnostics, and document tools.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceEnables controlling an Android device from an MCP client via ADB, including wireless debugging discovery, UI-tree inspection, and performing taps, swipes, typing, app actions, and shell commands without relying on screen coordinates.8 npmMIT
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to remotely control a real Android phone over MCP with no ADB, root, or emulator, by connecting a broker server to a sideloaded APK. Exposes tools to list devices, capture screenshots, read the UI tree, open links and deep links, and perform taps, swipes, typing, and global navigation actions.1MIT
- AlicenseBqualityCmaintenanceEnables any MCP assistant to see and operate an Android phone or emulator over plain adb, reading the accessibility tree to tap elements by name and also supporting screenshots, typing, swiping, app launching and installation, and logcat — with nothing installed on the device and no root required.13MIT
- AlicenseNot gradedqualityAmaintenanceEnables MCP-compatible AI assistants to see and control Android devices via ADB and scrcpy, exposing 44 tools for screenshots, taps, swipes, typing, UI element discovery, app management, file transfer, clipboard, shell commands, and audio/video streaming. Uses scrcpy's binary control protocol for fast input and near-instant screenshots, with an ADB fallback when no scrcpy session is active.357 npmMIT