voice-android-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| ADB_PATH | No | Full path to the adb executable. Defaults to `adb` on PATH. | adb |
| TAP_MODE | No | How buttons are pressed: `adb` for plain ADB taps, or `voice` to press buttons by speaking to Voice Access. | adb |
| VOICE_MIC | No | Input device for the `listen` tool: `phone`, or a PC microphone index or name part. | auto |
| EDGE_VOICE | No | Neural voice name used when `TTS_ENGINE=edge`, e.g. `en-US-AriaNeural` or `en-US-GuyNeural`. | en-US-AriaNeural |
| TTS_ENGINE | No | Text-to-speech engine: `edge` for the Microsoft neural voice (online, best recognised) or `sapi` for the built-in Windows voice. | edge |
| TTS_OUTPUT | No | Speaker used for spoken commands: speaker index or name part, e.g. `Realtek`. Use `list_speakers` to list available speakers. | Windows default |
| VOICE_LANG | No | Language used by the `listen` tool, e.g. `en-US`, `fr-FR`, or `ar-MA`. | en-US |
| VOICE_ENGINE | No | Speech recogniser for the `listen` tool: `google` (online) or `whisper` (requires `uv sync --extra whisper`). | |
| ANDROID_SERIAL | No | The Android device serial to use when several devices are connected. | |
| VOICE_CMD_RATE | No | Speed of spoken commands, from -10 (slow) to 10 (fast). | -2 |
| TTS_LEAD_SECONDS | No | Silence inserted before each spoken phrase so the speaker does not clip the first word. | 0.5 |
| SCREENSHOT_MAX_SIDE | No | Maximum side length of screenshots sent to Claude. Smaller values are cheaper. | 1280 |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
Control a real Android phone over ADB.
How to work:
Call
screenshotto SEE the screen. It returns an image with numbered boxes on tappable elements, plus a list like[7] button "Send" at (612,1430).Act: prefer
tap_element(7); usetap(x, y)with screenshot pixel coordinates when the thing you want has no number. Useopen_app,type_text,press_key,scroll.Call
screenshotagain to check the result before the next step. Never assume a tap worked. All x/y coordinates are in the pixel space of the latest screenshot image (the server converts).
Voice: listen records the user's voice from the PC microphone and returns the text;
speak says a reply out loud. For a hands-free assistant loop use the voice_assistant prompt.
Ask before sending messages, making calls, paying, deleting, or changing security settings.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| list_devicesA | List Android devices connected over USB or Wi-Fi, and which one is selected. |
| select_deviceC | Choose which device to control when more than one is connected. |
| connect_wifiB | Connect to a phone over Wi-Fi ADB, e.g. "192.168.1.20:5555" (phone must have wireless debugging on). |
| screenshotA | Take a screenshot of the phone so you can see what is on screen. With show_elements=True (default) tappable elements are boxed and numbered on the image, and a numbered list is returned: use tap_element(number) to press one. Coordinates in the list match the image pixels; pass them to tap(x, y) if needed. |
| get_ui_elementsA | Get the numbered list of on-screen elements (text, buttons, inputs) without an image. Cheaper than screenshot. |
| current_appA | Return the package/activity currently in the foreground. |
| tap_elementA | Tap element number |
| tapB | Tap at (x, y) in screenshot image pixels. |
| long_pressC | Long-press an element number ( |
| swipeC | Swipe from (x1,y1) to (x2,y2) in screenshot pixels. |
| scrollB | Scroll the screen. direction: down (see content below), up, left, right. amount: 0.1-0.9 of the screen. |
| type_textA | Type text into the focused field (tap the field first). submit=True presses Enter afterwards. |
| press_keyA | Press a key: home, back, enter, delete, recent, power, volume_up, volume_down, tab, wake, notifications, quick_settings, or any KEYCODE_* name. |
| open_appB | Open an app by name ("whatsapp", "camera", "settings") or package name ("com.whatsapp"). |
| list_appsB | List launchable apps (package names). Optional filter substring. |
| open_urlB | Open a URL or deep link (https://..., tel:..., geo:..., whatsapp://...) on the phone. |
| wake_and_unlock_swipeA | Turn the screen on and swipe up to dismiss the lock screen (works only without PIN/pattern). |
| waitA | Wait for the screen to settle (app loading, animations). Max 30 s. |
| adb_shellC | Run a raw |
| listenB | Listen to the user's voice and return what they said as text. mic: "phone" (the phone's own microphone, streamed over ADB) or "pc" (PC microphone).
Default comes from VOICE_MIC. Signals start with a beep (PC) and a short vibration (phone mode),
waits up to |
| voice_tapA | Press a button BY VOICE: the PC speakers say "click " and the phone's Voice Access taps it. Give ONE of: index - number of OUR coloured box / list entry from the latest screenshot (its name is spoken) label - the button's visible text, e.g. "Send" va_number - a Voice Access number: the small GREY PIN numbers drawn on the phone screen itself (visible in the screenshot when Voice Access "show numbers" is on). Best for icons without text and for long or ambiguous names. verb: click (default; avoid "tap", which Voice Access can confuse with app names), long press, double tap. Always take a screenshot afterwards: Voice Access shows a black toast like "Tapped connections". |
| voice_commandC | Say any Voice Access command out loud from the PC speakers, e.g. "scroll down", "go back", "go home", "open WhatsApp", "show numbers", "tap 5", "hide numbers", "show grid", "stop listening". |
| voice_access_statusA | Check that Google Voice Access is installed and enabled on the phone. |
| list_speakersA | Show the PC speakers and which one voice commands play through (set TTS_OUTPUT to change). |
| list_microphonesA | Show the PC microphones and which one |
| speakB | Say text out loud on the PC speakers (to report what you did or ask a question). |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
| voice_assistant | Hands-free mode: listen to voice commands and carry them out on the phone, in a loop. |
| phone_task | Do a task on the phone by looking at screenshots and pressing buttons by voice (Voice Access). |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 26 tools
Most tools have clear distinct purposes, but several boundaries blur: voice_tap is effectively a special case of voice_command ('tap 5'), tap_element is a convenience wrapper over tap whose index also works in long_press, and adb_shell can do almost anything the specialized tools do. Screenshot vs get_ui_elements are distinguishable but closely coupled, and an agent could reasonably pick the wrong voice tool or gesture tool.
All names are snake_case and readable, but the set mixes bare verbs (tap, swipe, scroll, speak, wait, listen) with noun/resource names (screenshot, current_app, adb_shell) rather than a uniform verb_noun pattern. wake_and_unlock_swipe and voice_access_status are compound but still understandable.
26 tools is on the heavy side for a single Android-control server; the core set (device/gesture/input/app tools) is justified, but peripheral tools like list_speakers, list_microphones, voice_access_status, and speak round out a surface that could be trimmed. It is borderline-heavy rather than clearly excessive given the broad device+voice domain.
The surface covers device discovery/selection, full UI interaction (tap, long press, swipe, scroll, type, keys), app/URL launching, shell escape hatch, and voice input/output with Voice Access. Minor gaps exist: no clipboard access, no file push/pull or app install/uninstall, no logcat/notification reading, and no pinch/multi-touch gesture, but agents can work around these via adb_shell.