Skip to main content
Glama

Mobilerun MCP

English · Tiếng Việt

A host-side Model Context Protocol (MCP) server that connects AI clients to Android (physical phones, emulators, redroid) over ADB and iOS through ios-portal. It focuses on device automation, screen perception, gestures, app management, and system intents — with all heavy lifting executed on the host, so nothing ARM-only has to run on the device.

This repo contains two cooperating pieces:

  • an MCP server providing 94 tools exposed over stdio or HTTP

  • the Mobilerun Portal accessibility service running on the Android device

Highlights

  • Host-side architecture: zero ARM-only dependency on device; runs seamlessly on physical devices, x86_64 emulators, and redroid containers

  • Zero-setup runner via npx with automatic Python runtime, virtual environment, and dependency provisioning

  • 94 exposed tools covering screen perception, gestures, apps, intents, notifications, media, and device control

  • Set-of-Mark (SoM) visual perception with numbered labels (som_id), accessibility tree, and OCR (Tesseract / OmniParser v2)

  • Built-in verification loop: every state-changing tool waits for the screen to settle and returns a post_action_observation

  • Direct compatibility with droidrun's mobilerun-core Device API for programmatic automation

  • Works over any network reachability supported by ADB (USB, Wi-Fi, LAN, VPN, adb connect)

  • Built-in configurable safety policies (off, standard, strict) protecting sensitive personal and financial data

Related MCP server: Karagöz

Requirements

  • Node.js >=18 (for zero-setup execution via npx)

  • adb (Android Debug Bridge, via platform-tools)

  • An Android device or emulator with USB debugging enabled

  • Python 3.10+ (optional, only needed for local source development)

  • Tesseract OCR (optional, for OCR on screens with sparse accessibility trees)

Installation and setup

1. Configure your AI client

Claude Code / Claude Desktop / VS Code / Cursor / Antigravity

Same server entry for all of them; only the file differs:

  • Claude Code — .mcp.json in your project root

  • Claude Desktop — claude_desktop_config.json

  • Cursor — .cursor/mcp.json

  • VS Code — .vscode/mcp.json (VS Code names the top-level key servers, not mcpServers)

  • Antigravity — MCP settings panel (MCP Store -> View raw config), backed by ~/.gemini/config/mcp_config.json, or .agents/mcp_config.json for a single workspace

{
  "mcpServers": {
    "mobilerun": {
      "command": "npx",
      "args": ["-y", "@impeterwayne/mobilerun-mcp@latest"],
      "env": {
        "MOBILERUN_DEVICE": "<serial>"
      }
    }
  }
}

Or via Claude Code CLI:

claude mcp add --scope user mobilerun -e MOBILERUN_DEVICE=<serial> -- npx -y @impeterwayne/mobilerun-mcp@latest

Note: MOBILERUN_DEVICE is optional if only one device is connected via ADB.

Codex CLI

~/.codex/config.toml:

[mcp_servers.mobilerun]
command = "npx"
args = ["-y", "@impeterwayne/mobilerun-mcp@latest"]
env = { MOBILERUN_DEVICE = "<serial>" }

OpenCode

opencode.json:

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "mobilerun": {
      "type": "local",
      "command": [
        "npx",
        "-y",
        "@impeterwayne/mobilerun-mcp@latest"
      ],
      "environment": {
        "MOBILERUN_DEVICE": "<serial>"
      },
      "enabled": true
    }
  }
}

2. Device setup and Portal install

Download and install the Mobilerun Portal APK on your Android device:

adb install -r <portal.apk>

Then enable the Mobilerun Portal accessibility service under Settings > Accessibility.

git clone https://github.com/Hi-im-Connect/mobilerun-mcp.git && cd mobilerun-mcp
uv venv --python 3.13 .venv && uv pip install -e .

On Windows, use .venv\Scripts\python.exe in place of .venv/bin/python.

In your MCP client configuration:

{
  "mcpServers": {
    "mobilerun": {
      "command": "/path/to/mobilerun-mcp/.venv/bin/python",
      "args": ["-m", "mobilerun_mcp"],
      "env": { "MOBILERUN_DEVICE": "<serial>" }
    }
  }
}

Available tools

94 tools covering screen perception, gestures, system control, notifications, media, and automation.

Screen perception and reading

Tool

What it does

perceive_screen

Captures an annotated screenshot with numbered marks (som_id) and list of interactive elements.

read_screen

ASCII/text grid representation of the screen and elements (settles screen before reading).

get_ui_tree

Compact accessibility hierarchy tree (classes, resource IDs, labels, flags, bounds).

get_screenshot

Returns current screenshot as base64 image data.

screenshot

Plain screenshot with optional overlay suppression.

screenshot_path

Takes a screenshot, saves it to a PNG file on disk, and returns the path.

Gestures, typing and input

Tool

What it does

tap

Tap at coordinates (x, y) or on a numbered element mark (som_id).

double_tap

Double-tap at (x, y) or on a numbered mark (som_id).

long_press

Press and hold at (x, y) or on a numbered mark (som_id) with configurable duration.

long_press_at

Long press at precise (x, y) coordinates.

swipe

Swipe between two coordinates (x1, y1) to (x2, y2) with duration control.

scroll_down

Scroll content downward (revealing content below).

scroll_up

Scroll content upward (revealing content above).

scroll_left

Scroll content to the left.

scroll_right

Scroll content to the right.

scroll

Directional scroll by custom fraction of the screen.

scroll_to

Scroll until target text or coordinates become visible.

type_text

Type text into the currently focused input field or target som_id.

type

Types text with optional typing speed (WPM) and clear options.

clear_input

Clears text from the currently focused input field.

press_home

Simulates pressing the physical/virtual Home button.

press_back

Simulates pressing the Back button (closes keyboards and popups).

press_enter

Simulates pressing Enter / Search / Submit.

open_recent_apps

Opens the recent applications overview switcher.

key

Dispatches hardware key codes or named keys (back, home, volume_up, wakeup, etc.).

press

Legacy button press helper (home, back, enter).

Tool

What it does

launch_app

Launch an application by fuzzy name or exact package name, waiting for foreground.

start_app

Starts an app by package ID and optional specific activity.

lookup_app

Search installed apps by name or package; returns ranked candidates with scores.

list_apps

Lists installed applications (user-installed and optional system apps).

list_app_deeplinks

Discovers available deep links and shortcuts for an app.

resolve_deeplink

Resolves which application handles a given URI or intent action.

open_deeplink

Opens a screen directly via URI, app shortcut, or intent action.

System intents, contacts, files and media

Tool

What it does

system_intent

Executes common Android intents (set alarm, navigate, dial phone, open browser).

resolve_contact

Finds contacts by partial name and returns phone numbers.

find_files

Searches the device media store (downloads, pictures, documents, videos).

open_file

Opens a file on device in its default application.

get_media_sessions

Retrieves active media playback sessions, track metadata, and volume.

media_control

Controls media playback (play, pause, next, previous, stop, rewind, fast forward).

volume_up

Increases media volume.

volume_down

Decreases media volume.

mute

Toggles media mute state.

Notifications

Tool

What it does

read_notifications

Reads active status-bar notifications with titles, text, and action buttons.

dismiss_notification

Dismisses a specific notification or clears all dismissible ones.

notification_action

Triggers a notification action button or sends an inline reply.

mobilerun-core Device API

Tool

What it does

ui

Full UI state snapshot (a11y_tree, phone state, device context).

ui_json

Serialized JSON string of the device UI hierarchy.

ui_with_recovery

UI snapshot with automatic retry logic for transient/reloading view hierarchies.

capabilities

Queries supported backend capabilities, actions, and platform information.

supports

Checks whether a specific action is supported on the target device.

screen_size

Returns device screen width and height in pixels.

current_app_id

Package name of the current foreground application.

time

Current device system time.

find_nodes

Finds nodes matching filters (text, ID, class, substring), including off-screen.

find_nodes_on_screen

Finds nodes matching filters strictly within visible screen bounds.

tap_text

Finds and taps the first visible node containing specific text.

tap_node

Taps the center of a node object returned from find_nodes.

tap_and_wait

Taps target element and waits for UI to become idle.

scroll_until

Continuously scrolls until an element matching criteria appears on screen.

assert_on

Asserts that a specific app package is currently in the foreground.

assert_text_visible

Asserts that expected text is visible within a timeout.

wait_for_app

Waits until the specified app package reaches the foreground.

wait_for_idle

Waits for screen animations and UI updates to finish settling.

wait_for_screen_change

Waits until UI changes from its current state.

wait_for_text

Waits until an element containing the specified text appears.

wait_for_nodes

Polls until nodes matching filters are detected.

open_and_settle

Launches an app and waits until it is fully loaded and idle.

stop_app

Force-stops an application with optional data clearing.

install_app

Installs an APK file from host storage onto the device.

uninstall_app

Uninstalls an application package.

grant_permission

Grants runtime permission (android.permission.*) to an app.

open_deep_link

Dispatches a deep link or view intent pinned to a package.

execute_script

Executes JavaScript within the foreground browser page.

get_clipboard

Reads current clipboard text content.

set_clipboard

Writes text content to the device clipboard.

Device management and connection

Tool

What it does

get_device_status

Comprehensive status: battery, screen state, foreground app, storage, IP.

list_devices

Lists available connected ADB devices and emulators.

ping_device

Verifies low-latency reachability of the device and Portal service.

connect_device

Re-establishes ADB and Portal connection for a target device.

disconnect_device

Disconnects a network/TCP ADB device and cleans up session state.

setup_portal

Installs and initializes the Mobilerun Portal service on the device.

doctor

Runs health diagnostics across ADB, device authorization, and the Portal.

request_screen_capture_permission

Compatibility check for screenshot capture permissions.

echo

Simple round-trip ping verifying MCP transport responsiveness.

adb

Executes raw ADB commands (disabled by default; requires MOBILERUN_MCP_ENABLE_ADB=1).

Planning, verification and research

Tool

What it does

verify_action

Verifies post-action outcomes against expected text or UI element state.

validate_action

Pre-validates planned actions against safety policy before execution.

wait_for

Configurable wait for long-running operations (downloads, uploads, page loads).

watch_device_events

Listens to device events (foreground app changes, notifications, keyboard).

web_search

Searches the web for application UI instructions and workflows.

set_plan

Initializes an execution plan checklist with goals and deliverables.

mark_step

Updates the status of a plan step (pending, in_progress, done, failed).

record_finding

Records key data points and evidence extracted during device interaction.

end_session

Concludes automation session and reports summary results.

get_usage_guide

Returns best practice instructions and tips for controlling devices.

Configuration

Variable

Default

Description

MOBILERUN_DEVICE

First connected device

Target ADB serial, network address (host:port), or ios

MOBILERUN_MCP_POLICY

off

Safety policy: off, standard (blocks banking/auth), strict (blocks credentials/PINs)

MOBILERUN_MCP_SCOPES

read,write

Tool scope restriction (read exposes only read-only inspection tools)

MOBILERUN_MCP_ENABLE_ADB

0

Set to 1 to expose raw adb shell execution tool

BRAVE_API_KEY

unset

API key for Brave search via web_search (defaults to DuckDuckGo)

TAVILY_API_KEY

unset

API key for Tavily search via web_search

MOBILERUN_DETECTOR_MODEL

Auto-downloaded

Local path override for OmniParser icon detection ONNX model

MOBILERUN_MCP_HTTP_HOST

127.0.0.1

Host address for HTTP MCP mode (--http)

MOBILERUN_MCP_HTTP_PORT

4816

Port for HTTP MCP mode (--http)

MOBILERUN_ADB_BIN

adb on PATH

Custom path to adb binary

Troubleshooting

Symptom

Fix

[device_unreachable] no device selected

Run adb devices, then set MOBILERUN_DEVICE=<serial> in your client config

adb devices shows unauthorized

Unlock the phone and tap Allow on the USB debugging authorization prompt

adb devices is empty or offline

Reconnect USB cable or run adb connect <host>:<port> for wireless/network devices

adb: command not found

Install platform-tools or specify binary location with MOBILERUN_ADB_BIN

Mobilerun Portal is not enabled

Enable in Settings > Accessibility > Mobilerun Portal, or run mobilerun setup -d <serial>

[stale_som_id] error

The screen changed after the last action; call perceive_screen or read_screen to refresh IDs

Client lists no mobilerun tools

Check client config file syntax and paths; restart the AI client

License

MIT. See LICENSE and NOTICE.

Available Tools

94 tools
assert_onAssert OnC

Fail unless app_id is in the foreground.

Inputs: app_id (required), device. Returns: object

assert_text_visibleAssert Text VisibleB

Fail unless text becomes visible on screen within timeout seconds.

Inputs: text (required), device, timeout. Returns: object

capabilitiesCapabilitiesC

Backend, platform and the actions this device supports.

Inputs: device. Returns: object

clear_inputClear InputC

Clear the focused text field.

Inputs: device. Returns: object

connect_deviceConnect DeviceB

(Re)connect adb and the Portal for a device; use after the network path came back.

Inputs: device. Returns: object

current_app_idCurrent App IdC

Package / bundle id of the foreground app.

Inputs: device. Returns: result

disconnect_deviceDisconnect DeviceB

Disconnect a TCP/IP adb device (adb disconnect host:port) and drop its session.

Inputs: device. Returns: object

dismiss_notificationDismiss NotificationC

Dismiss one notification (by key, or package/title) or every clearable one.

Inputs: key, title, device, package, +1 more. Returns: object

doctorDoctorC

Health check of adb, the Portal and the device (mobilerun doctor).

Inputs: device. Returns: object

double_tapDouble TapC

Double-tap at (x, y) or a mark.

Inputs: x, y, device, som_id. Returns: object

echoEchoA

Returns text verbatim: a check that the MCP transport is alive (no device access).

Inputs: text, message. Returns: object

end_sessionEnd SessionA

Mark the end of the task (the server keeps listening; the next call starts fresh). reason: short summary of what was done. outcome: success (goal state verified) | partial | failure. goal_type: play_media | send_message | send_email | purchase | post | open_app | search | navigate | other. For send_message, send_email, purchase and post, success is refused unless you looked at the screen (read_screen / perceive_screen) after your last action. Success is also refused while fewer findings than the plan's target_count are recorded. failure is never refused.

Inputs: device, reason, outcome, summary, +1 more. Returns: object

execute_scriptExecute ScriptC

Run JavaScript in the foreground browser page and return its JSON result.

Inputs: js (required), device.

find_filesFind FilesA

Search the device's media index by name, newest first: images, videos, audio and documents (downloads included). kind: image | video | audio | document | any. Returns content:// URIs for open_file (limit default 10, cap 25). With path, searches that shared-storage folder by file name instead (any file type).

Inputs: kind, path, limit, query, +2 more. Returns: object

find_nodesFind NodesA

Nodes matching every given filter (exact text/desc/resource_id/class_name, or *_contains substrings), including off-screen ones.

Inputs: desc, text, tree, device, +5 more. Returns: result

find_nodes_on_screenFind Nodes On ScreenC

Like find_nodes, limited to nodes inside the visible screen.

Inputs: desc, text, tree, device, +5 more. Returns: result

get_clipboardGet ClipboardC

The clipboard's text (Android needs the Mobilerun Keyboard as the active IME).

Inputs: device. Returns: result

get_device_statusGet Device StatusB

Battery, screen power, foreground app, size, storage, network addresses, volume.

Inputs: device. Returns: object

get_media_sessionsGet Media SessionsC

Active media sessions (app, playback state, title/artist) and the music volume.

Inputs: device, include_system. Returns: object

get_screenshotGet ScreenshotC

Plain screenshot as an image.

Inputs: device.

get_ui_treeGet Ui TreeC

Compact accessibility tree (class, id, label, flags C/L/E/S/K/P, bounds).

Inputs: device, max_depth. Returns: object

get_usage_guideGet Usage GuideB

How to use this server well. Topics: overview, shortcuts, text_entry, failures, ledger, safety, stop, efficiency, full.

Inputs: topic. Returns: object

grant_permissionGrant PermissionC

Grant a runtime permission (android.permission.*) to an app.

Inputs: package (required), permission (required), device. Returns: object

install_appInstall AppC

Install an APK (host path) on the device.

Inputs: path (required), device, replace, grant_permissions. Returns: object

keyKeyC

Press a key by mobilerun-core name (back, home, menu, enter, delete, escape, tab, space, search, page_up, page_down, volume_up, volume_down, wakeup, media_play_pause, ...) or by Android keycode number.

Inputs: name_or_code (required), device. Returns: object

launch_appLaunch AppA

Open an app by name (fuzzy) or exact package_name. An ambiguous name returns ranked candidates instead of guessing. If the app is already in the foreground it is left as is (already_foreground=true) unless force=true.

Inputs: force, device, package, app_name, +1 more. Returns: object

list_appsList AppsA

List installed apps (user apps only unless include_system_apps=true). include_protected_apps is honoured on Mobilerun Cloud devices only (as in mobilerun-core).

Inputs: device, system, include_system_apps, include_protected_apps. Returns: object

list_devicesList DevicesA

Devices you can control. scope: local (adb devices) | cloud (Mobilerun Cloud, needs MOBILERUN_CLOUD_API_KEY) | all. Cloud filters: state (creating, assigned, ready, terminated, ...), type, name, country, page, pageSize (or a filters dict). Any listed id works as the device argument of every tool.

Inputs: name, page, type, scope, +4 more. Returns: object

long_pressLong PressB

Press and hold at (x, y), a mark (som_id) or a get_state element (index). Hold time: duration_ms or ms (default 1000).

Inputs: x, y, ms, index, +3 more. Returns: object

long_press_atLong Press AtC

Long press at (x, y) (mobilerun agent action).

Inputs: x (required), y (required), device. Returns: object

lookup_appLookup AppC

Search installed apps by name or package; returns ranked candidates with scores.

Inputs: limit, query, device, app_name. Returns: object

mark_stepMark StepA

Update a plan step: pending | in_progress | done | skipped | failed. Put facts you read off the screen in note; the pixels are gone next turn.

Inputs: index (required), status (required), note, device. Returns: object

media_controlMedia ControlB

Control playback in any app without touching the screen: play, pause, play_pause, next, previous, stop, rewind, fast_forward. Goes to the active media session; package_name (from get_media_sessions) is checked against it and reported.

Inputs: action, device, command, package_name. Returns: object

muteMuteB

Toggle mute on the media stream (muted=true/false forces a state). Muting remembers the previous level for unmute.

Inputs: muted, device. Returns: object

notification_actionNotification ActionB

Tap one of a notification's own buttons (reply, archive, stop...); reply_text fills an inline reply field and sends it. Best-effort: it drives the notification shade.

Inputs: action (required), key, title, device, +2 more. Returns: object

open_and_settleOpen And SettleB

Start an app and wait until it is in front and idle.

Inputs: app_id (required), idle, device, timeout. Returns: object

open_fileOpen FileB

Open a file in its default viewer. uri: a content://media/... URI from find_files (never build one by hand); path: a file under shared storage.

Inputs: uri, path, device. Returns: object

open_recent_appsOpen Recent AppsC

Open the recent-apps overview.

Inputs: device. Returns: object

perceive_screenPerceive ScreenB

LOOK at the screen: an annotated screenshot plus every element and its tap point.

e is an array whose INDEX is the som_id (first entry = som_id 1): [center_x, center_y, name, flags] (name/flags omitted when empty). elements is the same list as text. Box colours: BLUE tappable, GREEN text input (type_text), MAGENTA scrollable, AMBER toggle, GREY nothing declared, RED on-host vision (detector/OCR; a good guess, not a fact). Flags (only when true): e editable, c checked, o unchecked, d disabled, f focused, l long-pressable, ? low-confidence vision box, w scroll host (aim inside it). offscreen: text that exists but is not on screen (cannot be tapped). detail="full" adds the visual pass (OmniParser YOLOv8 icon detector + OCR) for icons the tree does not describe; perception_tier reports tree_only or full. description is logged only. ids go stale after any action.

Inputs: ocr, lang, detail, device, +3 more.

ping_devicePing DeviceC

Is the device reachable? For adb devices, reports the Portal transport (http or content_provider).

Inputs: device. Returns: object

pressPressA

Press home, back or enter (kept for old clients; prefer press_home/back/enter).

Inputs: button (required), device. Returns: object

press_backPress BackB

Press Back (also closes the keyboard without leaving the screen).

Inputs: device. Returns: object

press_enterPress EnterA

Press Enter (submits search bars and forms).

Inputs: device. Returns: object

press_homePress HomeC

Press the Home button.

Inputs: device. Returns: object

read_notificationsRead NotificationsA

Current status-bar notifications, newest first, without touching the screen: key, app, title, text, action labels. Ongoing ones (music, navigation, downloads) only with include_ongoing=true; package_name filters to one app; limit default 20, cap 30. With the safety policy on, banking and authenticator notifications are withheld.

Inputs: limit, device, package, package_name, +1 more. Returns: object

read_screenRead ScreenA

Read the screen now (waits for it to stop moving first): the screen drawn as a character grid, each element a box with its som_id and label, then a table of what can be acted on: som (tap by this), in (som_id of the smallest box containing it), flg, label (only when it did not fit on the grid). Flags: * tappable, e text input (type_text, not tap), S scrollable, c toggle ON, o toggle OFF, l long-pressable, d disabled, - nothing declared (usually still tappable). N+k = som_id N plus k more elements with exactly those bounds; tap N. Header IDLE/BUSY: BUSY means it was still moving when the wait expired. Use perceive_screen instead for how something looks, when this ends with ESCALATE, or when what you need is missing.

Inputs: device. Returns: result

record_findingRecord FindingB

Record one item you found. quote must be copied exactly from the CURRENT screen.

Inputs: item (required), quote (required), device. Returns: object

request_screen_capture_permissionRequest Screen Capture PermissionA

Compatibility no-op: screenshots use the Portal / adb screencap, no prompt is needed.

Inputs: device. Returns: object

resolve_contactResolve ContactA

Find contacts by (partial) name and return their phone numbers.

Inputs: name (required), limit, device. Returns: object

screenshotScreenshotC

Plain screenshot. hide_overlay hides the Portal's element overlay first.

Inputs: device, hide_overlay.

screenshot_pathScreenshot PathC

Take a screenshot, save it as a PNG file and return the path.

Inputs: device. Returns: object

screen_sizeScreen SizeD

[width, height] in pixels.

Inputs: device. Returns: result

scrollScrollC

Scroll the content in direction (up | down | left | right) by distance (fraction of the screen). verify=true reports whether the screen actually moved (mobilerun-core).

Inputs: direction (required), ms, device, verify, +1 more. Returns: object

scroll_downScroll DownB

Scroll the content down (reveal what is below): a centered swipe over half the screen (amount), or inside a scrollable mark (som_id).

Inputs: amount, device, som_id. Returns: object

scroll_leftScroll LeftC

Scroll the content left (reveal what is to the left).

Inputs: amount, device, som_id. Returns: object

scroll_rightScroll RightB

Scroll the content right (reveal what is to the right).

Inputs: amount, device, som_id. Returns: object

scroll_toScroll ToA

Two modes. With x1, y1, x2, y2: drag the content from one point to the other (precise scroll). With text: scroll in direction until an element containing text is visible and return its mark.

Inputs: x1, x2, y1, y2, +5 more. Returns: object

scroll_untilScroll UntilC

Scroll until a matching node is on screen; result is the node (or null).

Inputs: text, device, settle, distance, +5 more. Returns: object

scroll_upScroll UpC

Scroll the content up (reveal what is above).

Inputs: amount, device, som_id. Returns: object

set_clipboardSet ClipboardC

Put text on the clipboard.

Inputs: value (required), device. Returns: object

set_planSet PlanC

Start a plan checklist. target_count > 0 means 'N items must be recorded' before end_session(success) is allowed. With 3+ steps and a search_query, the first web search rides along in the reply.

Inputs: steps (required), goal, device, deliverable, +2 more. Returns: object

setup_portalSetup PortalC

Install and enable the Mobilerun Portal on the device (mobilerun setup); path installs a specific Portal APK.

Inputs: path, device. Returns: object

start_appStart AppC

Start an app by id (Android package / iOS bundle id), optionally a specific activity.

Inputs: app_id, device, package, activity. Returns: object

stop_appStop AppB

Force-stop an app; clear_data also wipes its data.

Inputs: app_id (required), device, clear_data. Returns: object

supportsSupportsC

Whether this device supports a Device action (e.g. execute_script, get_clipboard).

Inputs: action (required), device. Returns: result

swipeSwipeB

Swipe from (x1, y1) to (x2, y2) over duration_ms / ms (default 300). mobilerun agent form: coordinate=[x, y], coordinate2=[x, y], duration in seconds.

Inputs: ms, x1, x2, y1, +6 more. Returns: object

system_intentSystem IntentA

One-call Android actions (action = the verb; verb= is accepted too). Verbs: set_alarm(hour, minute, label), set_timer(seconds, label), dial(phone_number), compose_sms(phone_number, body), add_calendar_event(title, start, end, location, notes; ISO datetimes), share_text(text, subject), navigate( destination, mode drive|walk|bike|transit). dial/compose_sms only prefill; the user sends.

Inputs: end, body, hour, mode, +15 more. Returns: object

tapTapC

Tap at (x, y) or at the center of a numbered mark (som_id from perceive_screen / read_screen). stealth=true uses mobilerun-core's humanized tap.

Inputs: x, y, device, som_id, +1 more. Returns: object

tap_and_waitTap And WaitB

Tap a text (or node) and wait until the UI has been idle for idle seconds.

Inputs: target (required), idle, device. Returns: object

tap_nodeTap NodeB

Tap the center of a node returned by find_nodes / find_nodes_on_screen.

Inputs: node (required), device, stealth. Returns: object

tap_textTap TextC

Tap the first on-screen node whose text/description contains text.

Inputs: text (required), device. Returns: object

timeTimeD

The device clock.

Inputs: device. Returns: result

typeTypeC

Type text (mobilerun). index taps that get_state element first; stealth=true types key by key like a person (mobilerun-core), at wpm words per minute.

Inputs: text (required), wpm, clear, index, +2 more. Returns: object

type_textType TextA

Type into the focused field (tap it first, or pass som_id). submit presses Enter after.

Inputs: text (required), clear, device, som_id, +1 more. Returns: object

uiUiC

Raw UI snapshot (a11y_tree, phone_state, device_context, ...), as Device.ui().

Inputs: device, filter. Returns: object

ui_jsonUi JsonC

The UI snapshot serialized as JSON text.

Inputs: device, filter, indent. Returns: result

ui_with_recoveryUi With RecoveryC

UI snapshot that retries past a dead or empty accessibility tree.

Inputs: device, filter. Returns: object

uninstall_appUninstall AppD

Uninstall an app.

Inputs: app_id (required), device. Returns: object

validate_actionValidate ActionB

Pre-check a planned action against the safety policy (and, for our action set, that its target exists) without doing it. gesture_type is the action (tap, type_text, launch_app, open_deeplink, ...); target is the app name/package, deep-link URI or text you plan to use. Returns allowed=false with a category for blocked apps and text.

Inputs: x, y, uri, text, +7 more. Returns: object

verify_actionVerify ActionC

Check an outcome against the live screen. kind: text (visible), gone (not visible), app (foreground package or name), activity, changed (the last action changed the screen).

Inputs: expected (required), kind, device, timeout, +1 more. Returns: object

volume_downVolume DownC

Lower the music volume by steps.

Inputs: steps, device. Returns: object

volume_upVolume UpC

Raise the music volume by steps.

Inputs: steps, device. Returns: object

wait_forWait ForA

LONG waits only (downloads, uploads, processing, status changes); gestures already settle. With text / package / activity: wait until that is on screen (gone=true: until it disappears). Otherwise wait until loading finishes (no progress bar or "Loading" text) and the screen is still; condition is echoed back, you judge the returned state. Timeouts: timeout_ms (default 5000, max 30000) / poll_interval_ms (default 500, min 100), or timeout / interval in seconds.

Inputs: gone, text, device, package, +6 more. Returns: object

wait_for_appWait For AppC

Wait until app_id is in the foreground.

Inputs: app_id (required), poll, device, timeout. Returns: result

wait_for_idleWait For IdleC

Wait until the UI stops changing.

Inputs: poll, device, timeout. Returns: result

wait_for_nodesWait For NodesC

Poll find_nodes until something matches (or timeout, returning []).

Inputs: desc, poll, text, device, +7 more. Returns: result

wait_for_screen_changeWait For Screen ChangeC

Wait until the UI differs from now.

Inputs: poll, device, timeout. Returns: result

wait_for_textWait For TextC

Wait until a node containing text exists (off-screen nodes count).

Inputs: text (required), poll, device, timeout. Returns: result

watch_device_eventsWatch Device EventsA

Collect device events for up to timeout_seconds (default 10, max 30), returning early once max_events (default 50) arrive: foreground app, keyboard, screen content, notifications posted/removed. kinds filters: foreground, keyboard, screen, notifications.

Inputs: kinds, device, duration, interval, +2 more. Returns: object

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

    TDQS

    C2.6/5.0

    Scored across 94 tools

    Disambiguation2/5

    Many tools overlap heavily: ui/ui_json/ui_with_recovery/get_ui_tree/perceive_screen/read_screen all return screen state, screenshot/screenshot_path/get_screenshot are near-duplicates, and tap/tap_text/tap_node/tap_and_wait plus press/press_home/press_back/press_enter/key blur action boundaries. The descriptions do hint at distinctions (raw vs annotated, coordinate vs text), but the sheer number of near-synonyms with legacy aliases ('kept for old clients', 'prefer ...') makes misselection likely.

    Naming Consistency4/5

    Almost everything follows a snake_case verb_noun convention (get_screenshot, launch_app, list_devices, press_home). Deviations are minor: bare nouns (ui, capabilities, time, echo), a single-word verb 'press' vs compound 'press_home', and a few legacy synonyms. Overall predictable and readable.

    Tool Count1/5

    94 tools is far beyond what a device-control surface needs, and much of the count comes from redundant aliases and overlapping variants (multiple screenshot tools, multiple screen-read tools, multiple tap/wait/key variants). This is an extreme mismatch that burdens selection.

    Completeness5/5

    Coverage is exhaustive: input gestures, UI perception, app lifecycle (install/uninstall/stop/grant), files, notifications, media, clipboard, device management, deep links, safety validation, and a task-planning/verification loop. Nearly every lifecycle operation for the domain is present with no obvious dead ends.

    Maintenance

    ActivitySlowing
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      C
      maintenance
      Enables AI agents to control, inspect, and automate Android devices, Waydroid containers, and AVD emulators over ADB. Provides tools for screenshots, UI-hierarchy text-based tapping, gestures, key presses, text input, app management, and raw shell commands.
      12
      MIT
    • A
      license
      B
      quality
      B
      maintenance
      Enables AI agents to automate Android and iOS devices, including emulators and physical devices, by capturing screenshots, reading UI accessibility trees, performing touch and text input, and managing app lifecycle and logs.
      18
      4
      MIT
    • A
      license
      Not graded
      quality
      A
      maintenance
      Enables AI agents to visually perceive and directly control Android devices via ADB and screen-control tooling, including screenshots, taps, swipes, typing, app management, UI inspection, file transfer, shell commands, and audio/video streaming.
      374 npm
      MIT