Skip to main content
Glama
uitree-local

uitree-local

by CT-mao

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 tools
delete_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.

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

    B3.2/5.0

    Scored across 30 tools

    Disambiguation3/5

    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.

    Naming Consistency4/5

    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.

    Tool Count2/5

    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.

    Completeness4/5

    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

    ActivityStale
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables 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 npm
      MIT
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables 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.
      1
      MIT
    • A
      license
      B
      quality
      C
      maintenance
      Enables 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.
      13
      MIT
    • A
      license
      Not graded
      quality
      A
      maintenance
      Enables 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 npm
      MIT