Skip to main content
Glama

Android Use

M8ven Score

Computer-use for Android. An MCP server that lets Claude see and operate a real Android phone — read the screen, tap, type, scroll, navigate settings, launch apps — from anywhere, over cellular. No root, no per-app API. Just the phone, driven the way a person drives it.

Think of it as the mobile counterpart to computer-use: instead of pixels and blind coordinate-guessing, it reads the phone's accessibility tree and hands the model a numbered list of what's actually on screen. The model acts by index.

Android Use driving a phone

App: com.android.deskclock
  [0] More settings <Button> @975,437
  [1] 7:00 AM / gym / Mon,Tue,Wed,Thu,Fri,Sat <item> [ON]  @540,835
  [2] 10:00 AM / pick up parcel / Today       <item> [OFF] @540,1101

"Turn off my gym alarm" becomes tap(1) — precise, cheap, and it survives layout shifts that break coordinate-based control.

Built for the people who find phones hard: an older relative in another city, anyone who doesn't know where a setting lives. "Why isn't my internet working?" → Claude diagnoses it and fixes it, over their mobile data, while they watch.

⚠️ This is a remote phone-control tool. Read SECURITY.md before you run it. Conservative defaults are on for a reason; don't strip them.

Why it's different

  • Accessibility tree, not screenshots. Real, labelled, tappable targets — far more reliable than asking a model to guess pixels. Screenshots are there as a fallback for videos, games, and canvas-drawn UIs.

  • The hard part, handled: Android splits a row across nodes — the tappable container carries no label, the label isn't tappable. Android Use folds each label into its nearest clickable ancestor, so one screen row = one entry.

  • Works from anywhere. Cellular + Tailscale means the phone needs no Wi-Fi and no cable — the case that actually matters when you're helping someone in another city.

  • Swappable transport. Every tool talks to one Backend interface. ADB (USB/Wi-Fi) today; an on-device companion app for the fully-remote, no-dev- options path. The 30+ tools never change when the transport does.

  • Types any language. The companion app uses ACTION_SET_TEXT, so Telugu, Hindi, emoji all work — adb shell input text can't do that.

Related MCP server: phone-use

How it works

Claude (Code / Desktop / claude.ai / mobile)
    │  MCP
    ▼
Android Use server  ──►  Backend interface
    │                      ├── AdbBackend      (USB or Wi-Fi, via adb)
    │                      └── AppBackend       (on-device app + HTTP bridge)
    ▼
your phone  ── accessibility service reads the screen, dispatches taps/gestures

Two ways to reach the phone:

  1. ADB — quickest to try. Plug in (or pair wirelessly), and it works.

  2. Companion app — a small Android app with an AccessibilityService and a token-authenticated bridge. No dev options, survives reboot, reaches the phone over Tailscale from anywhere, and can repair its own service remotely.

Quick start (ADB, 2 minutes)

git clone https://github.com/bsaisuryacharan/android-use && cd android-use
uv venv && uv pip install -e .

# phone: Settings → About → tap Build number ×7 → Developer options → USB debugging
adb devices          # should list your phone

# register with Claude Code
claude mcp add -s user android-use -- "$PWD/.venv/bin/python" -m android_use.server

Restart Claude Code, then just talk: "what's on my phone screen?", "turn off my 7am alarm", "open YouTube and search for lo-fi".

For the fully-remote path (companion app + Tailscale + claude.ai connector), see SETUP_APP.md, CONNECTOR.md, and MULTI_DEVICE.md.

Tools (30+)

get_screen / take_screenshot

Read the screen as a numbered list, or as an image

tap / tap_text / tap_coordinates

Act by index, label, or pixel

scroll / type_text / press_key

Navigate, type, hardware keys

open_app / list_apps

Launch apps (allowlist-enforced)

open_settings

Jump straight to a Settings page (wifi, battery, …)

check_internet

Diagnose connectivity without touching the screen

list_phones / add_phone / lock_phone

Drive several phones, named, isolated

repair_phone

Re-enable the accessibility service remotely

chrome_*

Drive Chrome via the DevTools protocol — real DOM, any language

Multiple phones are named and never confused; every result says which phone it touched, and you can hard-lock to one.

Honest limitations

  • Setup is the hard part, especially the companion app on Android 13+ ("restricted settings" blocks sideloaded accessibility apps until you allow it via App info → ⋮). This is the real barrier for non-technical users.

  • A PIN/pattern lock can't be bypassed — the owner unlocks the phone.

  • Secure screens block reads — banking apps often set FLAG_SECURE.

  • Tokens are plaintext and rotate on reinstall. Pairing UX is rough.

  • Google restricts accessibility apps on the Play Store; distribution is a real consideration, not a formality.

See SECURITY.md for the threat model and responsible-use policy.

Status

Working prototype. Verified end-to-end on vivo (Funtouch/Android 15) and a Pixel 9 emulator (Android 16), driven from Claude Code, Claude Desktop, and claude.ai over cellular. Contributions welcome — especially OEM compatibility, onboarding UX, and the security items in SECURITY.md.

License

Apache 2.0.

Available Tools

38 tools
add_phoneA

Register a phone so it can be driven by name.

host is its Tailscale address (see discover_phones) and token is the pairing token shown in the Android Use app on that phone.

Inputs: host (required), name (required), token (required), port, +1 more. Returns: result

check_deviceA

Check that a phone is reachable and report what it is. Call this first if anything seems wrong. Connects over Wi-Fi automatically if it can.

Inputs: device. Returns: result

check_internetA

Diagnose the phone's internet connection without touching the screen. Start here for 'my internet isn't working' - it shows whether the radios are on, whether traffic flows, and whether DNS resolves.

Inputs: device. Returns: result

chrome_clickB

Click an element by its number from chrome_read.

Inputs: index (required), device, tab_id. Returns: result

chrome_close_tabB

Close a Chrome tab by its id from chrome_tabs.

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

chrome_javascriptA

Run JavaScript in a Chrome tab and return the result. Use for anything the other chrome_ tools do not cover - extracting data, submitting a form, scrolling to an element.

Inputs: expression (required), device, tab_id. Returns: result

chrome_navigateC

Point an existing Chrome tab at a different URL.

Inputs: url (required), device, tab_id. Returns: result

chrome_openC

Open a URL in a new Chrome tab on the phone.

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

chrome_readA

Read a page in Chrome as structured content: its text plus a numbered list of links, buttons and fields. This is the web equivalent of get_screen, and far more reliable than reading the page off a screenshot.

Inputs: device, tab_id. Returns: result

chrome_tabsA

List the tabs open in Chrome on the phone. Use the ids with the other chrome_ tools; most of them default to the most recent tab.

Inputs: device. Returns: result

chrome_typeA

Type into a field in Chrome. Give the field's number from chrome_read, or omit it to type into whatever is already focused.

Unlike the phone's own keyboard, this handles any language and emoji.

Inputs: text (required), index, device, tab_id. Returns: result

connect_wirelessA

Connect to an already-paired phone over Wi-Fi. Use after the phone reboots or wireless debugging is toggled - the port changes each time, so this rediscovers it.

Inputs: device. Returns: result

disconnect_wirelessA

Drop the wireless connection. The pairing is remembered, so connect_wireless will reconnect without pairing again.

Inputs: device. Returns: result

discover_phonesA

Look for phones on your tailnet that are running the client app.

Finds Android devices on the tailnet and checks whether each answers on the bridge port. A phone found here still needs its pairing token before it can be driven - read that from the Android Use app on the phone itself.

Inputs: no named parameters. Returns: result

enable_wirelessA

Switch a cabled phone over to Wi-Fi so the cable can be unplugged.

Needs the phone plugged in for this one step, but no pairing code. Use this when the user wants to stop using the cable. It does not survive a phone reboot - pair_wireless does.

Inputs: device. Returns: result

forget_phoneB

Remove a phone from the registry. The phone itself is left untouched.

Inputs: name (required). Returns: result

get_screenA

Read what is currently on the phone screen, as a numbered list of tappable elements. This is the main way to see the phone - call it before acting, and after anything unexpected.

Inputs: device. Returns: result

list_adb_devicesA

Phones reachable over ADB from this machine - cable or wireless debugging.

Only useful while setting a phone up locally. Day-to-day the phones are reached over the network, not ADB.

Inputs: device. Returns: result

list_appsB

List the apps installed on the phone and which ones this server is allowed to open.

Inputs: device. Returns: result

list_devicesA

Find phones that could be added: devices on your tailnet running the client app. This is the normal way to discover a phone.

ADB is only relevant while setting a phone up from this machine; use list_adb_devices if you specifically need that.

Inputs: device. Returns: result

list_phonesA

List the phones this server can drive, and whether each is reachable.

Every other tool takes an optional device naming one of these. With more than one phone configured, always name the one you mean.

Inputs: no named parameters. Returns: result

lock_phoneA

Work on one phone only, until unlocked.

Every tool then acts on this phone, and a request naming a different one is refused rather than redirected. Use this when helping one person, so a misread instruction cannot reach somebody else's phone.

Inputs: name (required). Returns: result

open_appA

Open an app by name, e.g. 'youtube' or 'chrome'. Only apps on the allowlist can be opened - call list_apps to see them.

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

open_settingsA

Jump straight to a Settings page instead of navigating there by hand. Pages: wifi, mobile_data, network, airplane_mode, hotspot, bluetooth, display, sound, battery, storage, apps, location, security, accessibility, date_time, language, privacy, notifications, about_phone, settings_home.

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

pair_wirelessA

Pair with a phone over Wi-Fi, once, so no cable is needed afterwards.

On the phone: Settings > Developer options > Wireless debugging > 'Pair device with pairing code'. Pass the ip:port and the 6-digit code it shows. Note that the pairing port differs from the connection port.

Inputs: code (required), address (required), device. Returns: result

phone_healthB

Check whether the phone is reachable and why not, if not.

Worth calling first when something stops working: the accessibility service can be switched off by the system without warning, and the failure looks like a network problem until you look.

Inputs: device. Returns: result

press_keyC

Press a hardware or system key. Common ones: back, home, recents, enter, delete, volume_up, volume_down.

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

repair_phoneA

Put the phone's accessibility service back when it has been switched off.

Android periodically revokes accessibility access from apps it did not install. The phone can re-enable its own service, so this works over any network including cellular - no cable, and nobody has to touch the phone.

Inputs: device. Returns: result

scrollA

Scroll the screen: 'down' to see what is further down the page, 'up' to go back, or 'left'/'right' to move between pages.

Inputs: device, direction. Returns: result

take_screenshotA

Take a picture of the phone screen. Use this when get_screen doesn't show what you need - videos, games, photos, or custom-drawn interfaces.

Inputs: device, max_width.

tapA

Tap an element by its number from get_screen. This is the normal way to tap - the index comes straight from the last get_screen listing.

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

tap_coordinatesA

Tap an exact pixel position. Only use this when an element has no index - for example something you found in a screenshot.

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

tap_textA

Tap the element whose label matches this text. Use when you know what the button says but not its index.

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

type_textB

Type text into the field that is currently focused. Tap a text field first.

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

unlock_phoneB

Stop working on just one phone, so all registered phones are usable again.

Inputs: no named parameters. Returns: result

use_phoneA

Set which phone the other tools act on when no device is named.

This changes the default for everyone using this server, so prefer naming the phone per call when you are switching between them.

Inputs: name (required). Returns: result

wake_screenA

Wake the phone and dismiss a simple swipe lock. A PIN, pattern or fingerprint lock cannot be bypassed - the user must unlock it themselves.

Inputs: device. Returns: result

watchdog_reportA

Show what the background watchdog last saw, including when the phone went down and whether a repair was attempted. Use this to answer 'has the phone been reachable?' without poking the phone right now.

Inputs: no named parameters. Returns: result

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    B3.3/5.0

    Scored across 38 tools

    Disambiguation4/5

    Most tools are clearly separated by domain (device discovery, connection, UI interaction, Chrome, phone management), but some overlap exists: check_device, phone_health, and watchdog_report all diagnose reachability, and unlock_phone/lock_phone are inverse operations that could be confused with disconnect_wireless. The descriptions help, but a few boundaries are fuzzy.

    Naming Consistency4/5

    The naming is predominantly verb_noun (check_device, list_devices, tap_text, open_app, chrome_read), with a consistent style. Minor deviations: 'watchdog_report' is noun-ish, 'use_phone' and 'lock_phone' are less descriptive, and the chrome_* prefix is a clear sub-pattern. Overall predictable and readable.

    Tool Count3/5

    38 tools is on the heavy side for a single server, though the scope is broad (device management, UI automation, Chrome automation, phone registry). The count feels bloated because several tools could be merged (e.g., check_device/phone_health/watchdog_report, or the wireless pairing cluster), but each tool does have a distinct function.

    Completeness4/5

    The server covers the full lifecycle: discovery, pairing, connection, screen interaction, app control, Chrome automation, and phone registry management. Minor gaps: no explicit tool for swiping/long-press, no way to get device logs, and no tool to manage the allowlist for open_app, but the core workflows are well covered.

    Maintenance

    ActivitySlowing
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables Claude or any MCP agent to see and operate a real Android phone over adb, with fast screen reads, tap/type/swipe actions, app launching, deep links, and brand-aware setup guidance, all without admin rights or an Android SDK.
      MIT
    • A
      license
      B
      quality
      B
      maintenance
      Enables coding agents to observe and control an authorized Android phone over ADB through MCP tools and a JSON CLI. It supports UI inspection, screenshots, taps, swipes, typing, key presses, app listing, and launching.
      13
      6
      MIT
    • A
      license
      B
      quality
      B
      maintenance
      Enables Claude to control an Android phone over ADB by viewing screenshots and UI hierarchy and performing taps, typing, key presses, app launches, alarms/timers, and notification reads, with safe-by-default access modes and gated destructive actions.
      7
      46 npm
      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