mcp-phone-use
Controls an attached Android phone over ADB: captures screenshots (with crop/zoom and grid), taps and long-presses by screen coordinates, swipes, types text, and sends key events and chords (including Ctrl+A/C/V) via a virtual HID keyboard. Also dumps and searches the live uiautomator UI tree and reports device info such as serial, model, Android version, and screen resolution.
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
mcp-phone-use
MCP stdio server that controls an attached Android phone over ADB — the phone twin of mcp-computer-use.
~/.pi/agent/mcp.json -> bun /workspace/mcp-phone-use/server.coffeeThe simple interface
Tool | What it does | Image? |
| Capture screen; | yes |
| Tap at x,y in the last image's pixels | yes (unless |
| Type text into the focused field ( | yes |
| Send a key, a chord ( | yes |
| Substring search over the live UI tree + tap centers | no |
| Live uiautomator tree (text, resource-id, content-desc, class, bounds, center, | no |
| serial / model / android / screen px | no |
| Clear a field (Ctrl+A+Delete, else long-press → Select all → Cut) | no |
| long press, swipe, ordered tap→text→keys | yes |
| escape hatch: status / attach / detach of the virtual keyboard | no |
Related MCP server: android-mcp-server
Virtual HID keyboard (the important part)
phone_type and phone_key send real keystrokes on a virtual HID keyboard the server creates and manages itself. Callers never attach or detach it.
How it works (all verified on a real device running Android 17, no root, no USB gadget, no BlueZ):
Android ships
/system/bin/hid(frameworks/base/cmds/hid), which writesUHID_CREATE2to/dev/uhidthroughlibhidcommand_jni.adb's
shelluid is in theuhidgroup:uid=2000(shell) ... groups=...,3011(uhid),...and/dev/uhidiscrw-rw---- uhid uhid. SELinux isEnforcingand it still works.adb shell hid -is kept alive with a pseudo-JSON stdin stream (register→delay→report), which creates a genuine input device:/dev/input/event4,Classes: KEYBOARD | EXTERNAL, visible indumpsys input,geteventshowsKEY_LEFTCTRL/KEY_AwithMSC_SCAN 000700e0.Because it is a physical keyboard to the OS, hardware-keyboard semantics work: Ctrl+A select-all, Ctrl+C/V/X, Tab, Escape, normal typing.
Measured comparison on the same field:
Method | Ctrl+A select-all | Typing | Notes |
| ✗ typed a literal | ✓ | API-level injection; apps ignore the injected meta |
| n/a | one key | works, but no modifiers |
virtual HID keyboard | ✓ (Ctrl+A then Delete wiped the whole field; Ctrl+C → Delete → Ctrl+V pasted it back) | ✓ (incl. | real device, real meta state |
The one gotcha: VID/PID
Use a VID/PID with no /system/usr/keylayout/Vendor_XXXX_Product_YYYY.kl, otherwise EventHub maps our HID usages through that vendor layout and every key silently does nothing. The first attempt used a well-known vendor pair (18d1:2c40) that ships on the tested device as a remote-control layout — keys reached the kernel and InputReader (KeyState (pressed): KEY_LEFTCTRL, KEY_A) but nothing reached the app. Default is now vid=0x1234 pid=0x9999 → falls back to Generic.kl (US layout).
Lifecycle
Attached implicitly by the first
phone_key/phone_type/phone_clear_text.Auto-detaches after
idleMs(default 240 s) so the phone does not keep a phantom keyboard.Killed on
SIGINT/SIGTERM; closing thehidprocess' stdin unregisters the device (EOF → unregister).If
/dev/uhidis denied (locked-down OEM builds), the server silently falls back toinput text/input keyevent/input keycombination.
Screenshot-quota loop
Read/locate with
phone_find_element/phone_ui_dump— text only, no image.Send input with
observe:false— no screenshot returned;phone_key/phone_type/phone_clear_textneed noscreenshotId.Batch:
phone_key { keys:"Delete", repeat:25, observe:false }= 25 backspaces, one call.Screenshot only when you must see pixels (or need a
screenshotIdfor coordinate taps).
Android 17 quirks (measured)
input long-pressdoes not exist (Unknown command: long-press) → long press = zero-distance swipe with duration:input swipe X Y X Y 1200.input keyeventaccepts key names;input keycombination [-t ms] <codes...>is the chord API but its meta state is ignored by most apps.uiautomator bounds are
bounds="[l,t][r,b]"(bracketed pairs) —scripts/ui-dump.pyhandles both; it also reportsfocused/selected.KEYCODE_CTRL_LEFTis 113 (not 291). HID side: left-ctrl is modifier bit0x01,Ais usage0x04, Left-Arrow is0x50(verified by cursor-position test).
Layout
server.coffee tool definitions + JSON-RPC wiring
shared/mcp-stdio.mjs minimal newline-delimited MCP stdio host
lib/adb.mjs device resolution, screencap/pull, uiautomator dump, shell, spawnShell
lib/hidkbd.mjs virtual HID keyboard: UHID register/report, HID usage tables, idle auto-detach
lib/phone.mjs taps, long-press, text, keys, clear_text, ui dump (HID preferred, adb fallback)
lib/views.mjs screenshotId registry (120s TTL), crop/point mapping, geometry guard
lib/schema.mjs tiny JSON-Schema subset validator
scripts/screenshot-view.py crop/scale/grid (Pillow)
scripts/ui-dump.py XML -> JSON elementsRun
bun /workspace/mcp-phone-use/server.coffee # stdio MCP server (also launched from mcp.json)
pi mcp list # validate the mcp.json entryRequires adb and python3 + Pillow (requirements.txt). Multiple devices: set ADB_SERIAL=<serial>.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
This server cannot be deployed
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.
Turns a phone into a camera+Bluetooth remote so AI assistants can see and control any PC.
Drive cloud Android phones on US mobile IPs. Read the screen, tap, type, install apps and run tasks.
Give your AI agent a real cloud Android phone: push APKs, drive it, get screenshots and logs.
Related MCP Servers
- AlicenseBqualityDmaintenanceEnables control of Android devices via ADB, allowing screenshot capture, touch simulation, and swipe gestures through natural language commands.22188 npm6MIT
- AlicenseBqualityFmaintenanceEnables Android device control via ADB and scrcpy, including device management, app management, file operations, shell commands, input simulation, screen mirroring, and UI element inspection.2551 PyPIApache 2.0
- AlicenseNot gradedqualityDmaintenanceEnables remote control of Android devices via ADB, including screen operations, input, app management, file transfer, and advanced tools like UI testing and performance analysis.25MIT
- FlicenseBqualityBmaintenanceEnables comprehensive Android device control over ADB, including UI automation, screen capture/recording, app management, file operations, and log/notification access, with a built-in permission system.71-