android-mcp
Provides tools for interacting with Android apps and devices via adb, enabling agents to launch and control apps, inspect UI elements, perform taps/swipes/typing, read logcat, detect crashes, and manage emulators or real devices.
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., "@android-mcp launch the dev app, tap the profile tab, and tell me if the screen changed"
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.
android-mcp
MCP server that lets an agent use the Android app you are developing, on a local emulator or a real device, the way
a person does: look at the screen, tap, swipe, type, press keys, wait for things to appear and read logcat. It drives
the devices through adb, so every device Android Studio sees works here too.
Only Android Studio dev builds
The server only works with apps installed by Run in Android Studio. A package qualifies when all of these hold
(read from dumpsys package):
DEBUGGABLE: a debug build.TEST_ONLY: Android Studio injectsandroid:testOnly="true"into builds started from the IDE, and such APKs can only be installed withadb install -t, never through the Play Store or the package installer. A./gradlew installDebugfrom the command line doesn't set it, so those installs are refused as well.initiatingPackageName=com.android.shell(Android 11+): installed over adb.
Enforcement:
launch_app,stop_app,clear_app_data,open_urlandlogcatonly accept such a package.Screen tools (
get_ui,screenshot,wait_for,tap,long_press,swipe,scroll,type_text,press_key) check the foreground activity first and refuse while any other app is in front. The exception is the system permission dialog, so runtime permission prompts of the dev app can be answered.When an action leaves the app (e.g.
press_key home), the response says so instead of showing the screen.There is no install tool: install via Android Studio.
Related MCP server: AndroidBuildMCP
On-device agent (fast UI reads)
The UI tree is read through Appium's UiAutomator2 server (appium-uiautomator2-server, Apache-2.0), which stays running on the device and keeps its accessibility connection open:
A UI read takes ~0.4 s instead of 2.5–3 s with
uiautomator dump, and it does not wait for the screen to become idle.Starting it costs ~2 s once per session. It is installed automatically the first time (two APKs:
io.appium.uiautomator2.serverandio.appium.uiautomator2.server.test). They are not dev builds, so the dev-app restriction never lets the tools drive them.Compose test tags are exposed as
id=(mapTestTagToResourceId).If the agent can't be started, the tree falls back to
uiautomator dump. SetANDROID_MCP_AGENT=0in the server's environment to always use the dump.Only one process can hold the accessibility connection, so the server is stopped before falling back to a dump, and other UiAutomator tools (Appium, Maestro) can't run against the device at the same time.
Remove it from a device with
adb uninstall io.appium.uiautomator2.server.test && adb uninstall io.appium.uiautomator2.server.
The APKs come from the npm dependency at install time; this repo does not redistribute them.
Setup
Requirements: Node 20+, the Android SDK platform-tools (adb) and, for AVDs, the emulator. The SDK is found
via $ANDROID_HOME, $ANDROID_SDK_ROOT, ~/Android/Sdk, ~/Library/Android/sdk or PATH.
npm install
npm run build
claude mcp add --scope user android -- node "$PWD/dist/index.js"During development npm run dev (tsx) runs the sources directly; rebuild and run /mcp → reconnect in Claude Code
after changes.
Real devices
USB: enable Developer options → USB debugging, plug in, accept the RSA prompt.
Wi-Fi (Android 11+): Developer options → Wireless debugging → Pair device with pairing code, then
adb pair <ip>:<pair-port>andadb connect <ip>:<port>.
When several devices are connected, every tool needs serial (from list_devices).
Tools
Area | Tools |
Devices |
|
Apps |
|
Observe |
|
Diagnose |
|
Act |
|
One coordinate space. Screenshots are downscaled so the long edge is at most 768 px (image tokens grow with the pixel count).
get_uireports element centres in the same space, and every x/y input uses it, so a point read off a screenshot can be tapped as is.screenshotwithregionreturns a sharper crop for reading small text; a crop's pixels are not screen coordinates.Stable refs. Every element has a
[ref]that stays the same across calls as long as the element keeps its identity (class, id, label). Refs start at a random base per server process, so refs from before a restart fail instead of hitting another element.Act + observe in one call. Action tools wait
settle_ms(300 ms default) and then report, by default (observe: "changes"), only what changed since the agent last saw the screen: added (+), changed (~) and gone (-) elements, or "No visible change". A new screen comes back in full.ui,screenshot,bothandnoneare available too.read_allscrolls a list or form to its end and returns all entries in one call, instead of one call (and one model turn) per scroll.Targets.
tap/long_press/type_texttakeindex(a[ref]),text(text or content description, substring unlessexact),id(resource id / Compose test tag), orx+y. Refs are looked up in a fresh read, so they always tap the element's current position.get_uioutput lists only visible elements that carry text, a description, a leaf id or an interaction flag. A clickable container without its own text shows its children's text as~"…", and those children are folded into it.all: trueshows every node.No tree? If neither the agent nor
uiautomator dumpdelivers a tree, the tools say so andget_uireturns a screenshot instead: continue with x/y taps.logcatfilters by the app's uid, so lines of a crashed earlier process are still included. By default each call only returns lines that are new since the previous call with the same filters.Crash notices. Every screen tool and
launch_app/open_urlcheck the app for new crashes, ANRs and native crashes after acting (~75 ms) and put a⚠ … crashed: <exception> at <frame>notice with theget_crashid in front of the result, or of the error if the action failed. Crashes that happen between two calls are reported with the next call; each crash is reported once.Animations off. On first use of a device the server sets the window, transition and animator duration scales to 0, so steps are faster and the UI is settled when it is read. The original values are restored when the server exits (also on SIGINT/SIGTERM and when the client closes stdin) and kept in
$TMPDIR/android-mcp-animations-<serial>.jsonmeanwhile, so a server that was killed hard doesn't make the next one treat 0 as original. If a server was killed hard (kill -9), the next server restores the device when it exits. SetANDROID_MCP_KEEP_ANIMATIONS=1to leave the settings alone.list_crashes/get_crashread the system DropBox (dumpsys dropbox): Java crashes, ANRs and native crashes of the app, newest first, each with exception and top frame;get_crashreturns the full report with the complete stack trace. Unlike logcat, these reports survive the process and log rotation.since_minuteslimits the list to recent crashes.start_emulatorwaits up to ~40 s per call (below the MCP request timeout); call it again to keep waiting. Emulator output goes to$TMPDIR/android-mcp-emulator-<avd>.log.
Token usage
Each tool call is one model turn, and every turn re-reads the whole conversation. Long UI sessions inside a big coding
conversation get expensive because of that, not because of the tool output. Run UI testing in a fresh session or in
a subagent with a small context: a ready-made Claude Code subagent definition (android-tester, Sonnet, android tools
only) can live in ~/.claude/agents/android-tester.md.
Typical loop
Install the app with Run in Android Studio, then
list_dev_apps.launch_app→ read the returned UI tree.tap/type_text/scrolland read the new state from each response;wait_fortext after navigation or loading instead of sleeping.list_crashesto see whether the app crashed,get_crashfor the stack trace, andlogcatwithlevel: "E"for errors that didn't crash it.
Limitations
type_textsupports printable ASCII only (adb shell input text). Usepress_key enterfor new lines.No multi-touch gestures (pinch). Zoom maps with double-tap or their zoom controls.
Compose test tags appear as
id=only if the app setsModifier.semantics { testTagsAsResourceId = true }at its root (worth enabling in debug builds); otherwise target Compose elements by text or content description.Screenshots take ~1 s (
screencap) and cost far more tokens than the tree; ask for them only where the tree is not enough.
Available Tools
23 toolsclear_app_dataA
Delete all data of an app (like a fresh install). Also stops it.
Inputs: package (required), serial.
current_appC
Package and activity currently in the foreground.
Inputs: serial.
get_crashB
Full report of one crash from list_crashes: header (process, version, time) and the complete stack trace.
Inputs: id (required), package (required), serial, max_lines.
get_screen_infoC
Screen size, density, coordinate scale and the app in the foreground.
Inputs: serial.
get_uiA
The visible UI as a list of elements: [ref] (stable across calls), text, desc, id, centre, size, flags. Target elements by ref (index), text or id. Falls back to a screenshot when no tree is available.
Inputs: all, serial.
launch_appC
Launch an allowed dev app by package (its launcher activity), or a specific activity of it.
Inputs: package (required), serial, observe, activity, +1 more.
list_crashesB
List recorded crashes, ANRs and native crashes of a dev app, newest first, with exception and top frame. Reports survive the process and logcat rotation.
Inputs: package (required), limit, types, serial, +1 more.
list_dev_appsA
List the apps this server may use. Only debug builds installed from Android Studio (Run) are allowed: debuggable + testOnly + installed via adb.
Inputs: serial.
list_devicesA
List connected adb devices (emulators and physical) and available AVDs.
Inputs: no named parameters.
logcatA
Read the log of an allowed dev app (including lines of crashed earlier processes). By default returns only lines that are new since the previous call with the same filters.
Inputs: package (required), grep, level, serial, +2 more.
long_pressB
Long-press an element (by index, text or id) or a screen point (x, y).
Inputs: x, y, id, text, +7 more.
open_urlB
Open a URL / deep link in an allowed dev app with an ACTION_VIEW intent.
Inputs: url (required), package (required), serial, observe, +1 more.
press_keyB
Press a key: back, home, enter, del, backspace, forward_del, tab, escape, app_switch, menu, search, power, wakeup, volume_up, volume_down, dpad_up, dpad_down, dpad_left, dpad_right, dpad_center, move_home, move_end, any KEYCODE_* name, or a key code number.
Inputs: key (required), serial, observe, settle_ms.
read_allA
Read a whole scrollable list or form in one call: scrolls it to the end and returns every entry it contains, in order. Much cheaper than scrolling step by step. Afterwards the list stays at the end.
Inputs: index, serial, direction, max_scrolls.
screenshotA
Take a screenshot (costs far more tokens than get_ui; use it for visuals the tree lacks). Its pixel coordinates are the screen coordinates every other tool uses. With region, returns a sharper crop for reading small text; a crop's pixels are NOT screen coordinates.
Inputs: region, serial.
scrollA
Scroll the content in a direction (down = reveal content below). Scrolls the given element (index), otherwise the largest scrollable element on screen (the screen centre only when no UI tree is available).
Inputs: direction (required), index, amount, serial, +2 more.
set_orientationA
Lock the screen to portrait or landscape, or re-enable auto-rotation.
Inputs: orientation (required), serial, observe, settle_ms.
start_emulatorA
Start an Android emulator (AVD) and wait until it has booted. Returns immediately if it is already running.
Inputs: avd (required), headless, cold_boot.
stop_appC
Force-stop an app.
Inputs: package (required), serial.
swipeA
Swipe/drag from one screen point to another. A slow swipe (duration >= 1000) acts like a drag.
Inputs: to_x (required), to_y (required), from_x (required), from_y (required), +4 more.
tapC
Tap an element (by index, text or id) or a screen point (x, y).
Inputs: x, y, id, text, +6 more.
type_textA
Type text into the focused field. Optionally tap a target first to focus it, clear it, and press enter afterwards.
Inputs: value (required), x, y, id, +9 more.
wait_forC
Wait until an element with the given text/id appears (or, with gone=true, disappears).
Inputs: id, gone, text, exact, +3 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 23 tools
Tools are well separated by resource and action: interaction (tap/long_press/swipe/scroll/type_text/press_key), capture (screenshot/get_ui), and diagnostics (logcat/list_crashes/get_crash) are clearly differentiated, and descriptions explicitly resolve the screenshot-vs-get_ui and read_all-vs-scroll boundaries. The only mild overlap is get_screen_info vs current_app, both of which report the foreground app, and get_ui vs read_all for reading content.
Most tools follow a predictable verb_noun pattern (open_url, get_ui, list_devices, start_emulator, launch_app, clear_app_data, press_key). A few deviate to bare nouns/actions (screenshot, logcat, tap, swipe, current_app), which is readable but not fully uniform.
At 23 tools it sits at the high end, but the surface is cleanly partitioned across device lifecycle, app lifecycle, UI interaction, capture and diagnostics, so each tool earns its place. It is slightly heavy but not bloated or redundant.
The set covers a full Android automation lifecycle: device/emulator management, app listing/launch/stop/clear-data, rich UI interaction, capture, and crash/log diagnostics, with sensible helpers like wait_for and read_all. Minor gaps remain (no install/uninstall or file push-pull, no multi-touch/pinch or double-tap gestures), but they are workaroundable.
Related MCP Connectors
Give your AI agent a real cloud Android phone: push APKs, drive it, get screenshots and logs.
Disposable cloud Android emulators for coding agents: run an APK or PR build, tap, type, screenshot.
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.
Let AI agents control Android and iOS devices on Mobilerun Cloud: screen, input, apps, workflows.
Related MCP Servers
- AlicenseAqualityDmaintenanceEnables an agent to inspect and interact with Android emulators or physical devices via ADB, capturing UI snapshots, tapping nodes, typing text, and reading app logs.10MIT
- AlicenseAqualityDmaintenanceEnables AI agents to build, deploy, drive, and debug Android apps — managing Gradle builds, emulators, adb deployment, logcat capture, and full UI automation.5376 npmMIT
- AlicenseAqualityBmaintenanceDrives an Android emulator or a physical device over adb. The agent screenshots, reads the UI hierarchy with true device-pixel coordinates, taps and types, manages app lifecycle, reads logcat, and runs Gradle builds and tests.8118MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI assistants and IDEs to drive real Android devices and emulators for cross-app UI automation, testing, and diagnostics, including collecting Logcat output and screenshots.Apache 2.0