MCP server that gives AI coding assistants (Claude, Cursor, Windsurf) the ability to see and interact with Android mobile devices via ADB — AI-powered visual inspection, element finding, and device automation
Server registers 37 tools with consistent use of verb_noun naming (analyze_screen, find_element, tap, swipe, etc.). Descriptions are present and reasonably detailed (averaging 150-250 chars), meeting the 10-1024 char range. Input schemas use Zod for validation and are explicitly defined with type and description fields. However, OUTPUT schemas are entirely undocumented, no tool specifies what fields it returns, forcing LLMs to infer structure. Error handling is basic (generic error responses without recovery guidance). Tool composition is good (separate concerns: analyze vs. interact), but several UI interaction tools lack important constraints (e.g., tap accepts any x/y without bounds checking or device resolution validation). Parameter descriptions are present but often terse. Security: no secrets in params observed, but no explicit permission gating. Several tools accept 'device_id' as a required parameter but there's no validation that it exists before execution, risking silent failures.
Uses AI vision to analyze the current screen of a mobile device. Returns a structured analysis including app name, screen type, interactive elements with coordinates, visible text, and suggested next actions. This is the primary tool for understanding what is currently displayed on the device.
Perform a double tap at the given (x, y) screen coordinates. Useful for zooming into maps/images or selecting text.
Uses AI vision to extract all visible text from the current screen. Returns text in reading order (top to bottom, left to right). Useful for reading content, checking labels, or getting text that isn't in the accessibility tree.
Uses AI vision to find a specific UI element by natural language description. Returns the element's coordinates, type, and confidence score. Use this when you need to locate a specific button, field, or other UI element. Example queries: 'the login button', 'email input field', 'the red error message'.
Discover and connect to a running Flutter app on the device via the Dart VM Service Protocol. The app must be running in debug or profile mode. Returns connection details including the isolate ID and app name. Call this before using other flutter_* tools. Optionally pass vm_service_url from 'flutter run' output if auto-discovery fails.
Output schemas completely undocumented. No tool specifies what fields it returns (e.g., analyze_screen's response structure, find_element's coordinate format, list_apps' app object schema). LLMs must infer structure, risking wrong field access and downstream tool call failures.
No input validation or range constraints on coordinate parameters (tap, double_tap, long_press, swipe). Parameters accept x/y as raw numbers without enforcing device resolution bounds. An LLM could pass out-of-bounds coordinates or negative values without immediate feedback.
Error responses lack recovery guidance. The generic 'Error in {tool}: {error}' response does not tell the LLM what to do next (retry? use a different tool? ask the user?). No categorization of retryable vs. fatal errors.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 57 | 2026-07-28+ | v2 |
Disconnect from the currently connected Flutter app and clean up resources.
Search the widget tree for widgets matching a query. Searches by widget type name, description, and text content. Example queries: 'ElevatedButton', 'Text', 'AppBar', 'Login'. Returns matching widgets with their source locations.
Map every user-created widget to its source code location (file:line:column). This is the key tool for connecting what you see on screen to where it is in code. Returns a list of {widget, file, line, column} entries.
Get detailed information about a specific widget by its valueId (obtained from flutter_get_widget_tree). Returns properties, children, render bounds, and source location.
Get the widget tree from the connected Flutter app. By default returns the summary tree (user-created widgets only), which maps directly to your source code. Each widget includes its type, properties, source code location (file:line), and children. Call flutter_connect first.
Get the package name and activity name of the app that is currently in the foreground on the device. Useful for determining what the user is currently looking at.
Get detailed information about a specific Android device, including model, manufacturer, Android version, SDK version, connection status, screen size, and whether it is an emulator.
Retrieve recent Android logcat entries from the device. You can filter by minimum log level (V=Verbose, D=Debug, I=Info, W=Warning, E=Error, F=Fatal) and/or by tag name. Returns structured JSON with timestamp, PID, TID, level, tag, and message for each entry.
View the actions recorded so far without stopping the recording. Useful for inspecting what has been captured.
Get the screen resolution of a connected Android device. Returns the width and height in pixels.
Install an Android application from an APK file on the host machine. Provide the full path to the .apk file. The APK will be pushed to the device and installed.
Boot an iOS simulator by its UDID. Get the UDID from ios_list_simulators.
List all available iOS simulators with their status (Booted/Shutdown), UDID, name, and iOS version. Works on macOS only.
Take a screenshot of a running iOS simulator. Returns the image as base64.
Shutdown a running iOS simulator by its UDID.
Launch an installed application by its package name (e.g. 'com.android.chrome'). The app will be started with its default/main activity. Use list_apps to discover available package names.
List all installed applications on the device. By default only user-installed (non-system) apps are returned. Set include_system to true to also include system apps. Each entry contains the package name, display name, version, and whether it is a system app.
List all connected Android devices and emulators. Returns an array of DeviceInfo objects including id, model, manufacturer, Android version, connection status, and whether the device is an emulator.
Perform a long press (touch and hold) at the given (x, y) screen coordinates. Commonly used to open context menus, start drag operations, or trigger secondary actions.
Press a hardware or system key on the device. Accepts friendly key names such as 'home', 'back', 'enter', 'volume_up', 'volume_down', 'power', 'tab', 'delete', 'menu', 'search', 'app_switch', 'dpad_up', 'dpad_down', 'dpad_left', 'dpad_right', 'camera', 'escape', 'space', 'media_play_pause', 'media_next', 'media_previous'. You may also pass a raw Android keycode number as a string (e.g. '3' for HOME).
Finds a UI element by natural language description and taps it. Combines element finding and tapping into a single action. Example: smart_tap('the Sign In button') will locate the button and tap its center coordinates. Returns whether the tap succeeded and which element was tapped.
Finds an input field by natural language description, taps it to focus, and types the specified text. Example: smart_type('email field', 'user@example.com') will find the email input, tap it, and type the email address.
Start recording all MCP tool calls to generate a reproducible test script. All subsequent tool calls will be logged until stop_test_recording is called.
Force-stop a running application by its package name. This immediately terminates the app process. Useful for resetting app state or freeing resources.
Stop recording and generate a test script from the recorded actions. Supports TypeScript, Python, and JSON output formats.
Uses AI to analyze the current screen and suggest a sequence of actions to achieve a specified goal. Returns step-by-step instructions with exact coordinates for each action. Example goals: 'log into the app', 'navigate to settings', 'add an item to cart'.
Perform a swipe gesture from (start_x, start_y) to (end_x, end_y). Use this to scroll through lists, dismiss notifications, navigate between pages, or pull down the notification shade. A shorter duration makes the swipe faster (flick), while a longer duration makes it slower (drag).
Perform a single tap at the given (x, y) screen coordinates. Use get_ui_elements first to find the centerX/centerY of the element you want to tap.
Type text into the currently focused input field on the device. Make sure an input field is focused first (tap on it). Special characters and Unicode are supported.
Uninstall an application from the device by its package name. This removes the app and all its data. System apps cannot be uninstalled without root access.
Uses AI to verify whether a specific assertion about the current screen is true. Returns a boolean result with confidence score and evidence. Example assertions: 'the login button is visible', 'there is an error message'.
Compares the current screen with a previous screenshot to identify what changed. Provide a base64 PNG screenshot as the 'before' image — the tool captures the current screen as the 'after' image. Returns a list of changes with descriptions and regions. Useful for verifying that an action had the expected effect.
No device_id validation before execution. Tools require device_id but never verify it exists or is accessible. A misspelled device ID silently fails with unhelpful errors like 'device not found' rather than listing available devices.
Destructive operations (uninstall_app, stop_app) lack confirmation/dry-run patterns. An LLM could force-stop a critical background service or uninstall the wrong app without a confirmation step.
Parameter descriptions for interactive tools (smart_tap, smart_type) lack guidance on element identification. Example: 'Description of the element to tap', unclear whether the LLM should use visible text, accessibility label, or visual context. No examples of successful queries.