Android Control MCP Server
# Android Control MCP Server
A production-ready **Model Context Protocol (MCP)** server built in Node.js that enables AI assistants (such as Claude Desktop, Cursor, and custom agentic workflows) to observe, reason about, and control connected Android devices.
---
## ๐ Features
- **๐ Computer-Use Observation**: High-resolution PNG screen capture returned directly as MCP image blocks alongside device metadata.
- **๐ UIAutomator Hierarchy Parsing**: Intelligent XML dump parser that transforms verbose Android UI trees into compact, structured JSON.
- **๐ฏ Semantic Element Clicking**: Click buttons and controls by their visible text, accessibility description, or resource ID without needing manual pixel calculations.
- **โก Fast Gestures & Input**: Pixel-accurate tapping, multi-coordinate swiping, directional scrolling, hardware key emulation, and shell-escaped text typing.
- **๐ฑ App Lifecycle Management**: Launch applications by package name and inspect the currently focused foreground activity.
- **๐ก๏ธ Safety & Sandboxing**: Input coordinate validation against actual screen bounds, strict allowlisted keycodes, argument sanitization, command timeouts, and strict `stderr` logging to guarantee stdio MCP stream integrity.
- **๐ Multi-Device Support**: Auto-detects connected devices or targets specific devices via `ANDROID_DEVICE_ID`.
---
## ๐๏ธ Architecture
```text
AI Client (Claude Desktop, Cursor, Agent)
โ
โ stdio transport (JSON-RPC)
โผ
Node.js MCP Server
โ
โโโ Stderr Structured Logger
โโโ Zod Schema Validation
โ
โโโ ADB Controller Layer
โ โโโ Device Resolver (auto-detect or target serial)
โ โโโ Input Engine (tap, swipe, keyevent, text, scroll)
โ โโโ Screenshot Manager (exec-out binary stream)
โ โโโ App Manager (launch, foreground inspection)
โ
โโโ UIAutomator Engine
โโโ XML Hierarchy Dump & Normalizer
โโโ Bounds & Center Coordinate Extractor
โโโ Semantic Element Finder & Click Resolver
โ
โผ
Android Device / Emulator
```
---
## ๐ Prerequisites
1. **Node.js**: `v20.0.0` or higher (`node -v`)
2. **Android SDK Platform-Tools**: ADB (`adb`) installed and accessible in your system `PATH` (or configured via `ADB_PATH`).
3. **Android Device or Emulator**:
- Physical Device: Connect via USB, enable **Developer Options** and **USB Debugging**.
- Emulator: Android Studio AVD, Genymotion, or headless emulator.
### Verify Device Connection
```bash
adb devices -l
```
You should see your device listed as `device`:
```text
List of devices attached
emulator-5554 device product:sdk_gphone64_arm64 model:sdk_gphone64_arm64
```
---
## ๐ Installation & Quick Start
```bash
# Clone or navigate to the repository
cd c:/Users/Abhishek/Code/mcp
# Install dependencies
npm install
# Run unit tests
npm test
# Start the MCP server
npm start
```
---
## โ๏ธ Configuration
Create a `.env` file or pass environment variables:
```env
# Target device ID (serial number). If omitted and 1 device is connected, it auto-selects.
ANDROID_DEVICE_ID=
# Custom path to ADB executable if not in PATH
# Windows: C:\Users\<user>\AppData\Local\Android\Sdk\platform-tools\adb.exe
# macOS: /Users/<user>/Library/Android/sdk/platform-tools/adb
ADB_PATH=adb
# Log level: debug | info | warn | error
LOG_LEVEL=info
# Default ADB timeout in milliseconds
ADB_TIMEOUT_MS=15000
```
---
## ๐ Connecting to MCP Clients
### 1. Claude Desktop Configuration
Add the following to your `claude_desktop_config.json`:
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
```json
{
"mcpServers": {
"android-control": {
"command": "node",
"args": ["C:/Users/Abhishek/Code/mcp/src/index.js"],
"env": {
"ANDROID_DEVICE_ID": "",
"ADB_PATH": "adb",
"LOG_LEVEL": "info"
}
}
}
}
```
### 2. Cursor / Windsurf MCP Configuration
In Cursor's **Features > MCP Servers** or Windsurf settings:
- **Name**: `android-control`
- **Type**: `command`
- **Command**: `node C:/Users/Abhishek/Code/mcp/src/index.js`
---
## ๐ ๏ธ MCP Tools Reference
### 1. `android_device_info`
Get comprehensive device hardware and OS metadata.
- **Parameters**:
- `deviceId` *(optional string)*: Target device serial.
- **Example Response**:
```json
{
"deviceId": "emulator-5554",
"model": "Pixel 8",
"manufacturer": "Google",
"androidVersion": "15",
"sdk": 35,
"resolution": {
"width": 1080,
"height": 2400
},
"connectionState": "connected"
}
```
---
### 2. `android_screenshot`
Capture the Android screen as an MCP Image Content Block (`image/png`).
- **Parameters**:
- `deviceId` *(optional string)*: Target device serial.
- **Returns**: PNG base64 image data block + dimension metadata.
---
### 3. `android_ui_dump`
Dumps the current screen UIAutomator hierarchy into a compact, AI-friendly JSON format.
- **Parameters**:
- `deviceId` *(optional string)*: Target device serial.
- **Example Output**:
```json
{
"package": "com.android.settings",
"activity": "com.android.settings.Settings",
"totalElements": 24,
"interactiveElementsCount": 8,
"elements": [
{
"index": 0,
"text": "Network & internet",
"resourceId": "android:id/title",
"className": "TextView",
"clickable": true,
"bounds": [196, 340, 1016, 400],
"center": [606, 370]
}
]
}
```
---
### 4. `android_find_element`
Search for UI elements matching specific criteria on the current screen.
- **Parameters**:
- `text` *(optional string)*: Visible text (exact or partial).
- `contentDescription` *(optional string)*: Accessibility label.
- `resourceId` *(optional string)*: Resource ID.
- `className` *(optional string)*: Widget class name.
- `clickable` *(optional boolean)*: Filter by clickability.
- `exactMatch` *(optional boolean, default `false`)*: Exact string match.
---
### 5. `android_click_element`
Find an element and click its center point in a single step.
- **Parameters**:
- `text` *(optional string)*: Element text.
- `contentDescription` *(optional string)*: Element content description.
- `resourceId` *(optional string)*: Element resource ID.
- `className` *(optional string)*: Element class.
---
### 6. `android_tap`
Tap at exact (x, y) coordinates with screen boundary validation.
- **Parameters**:
- `x` *(number)*: X coordinate.
- `y` *(number)*: Y coordinate.
---
### 7. `android_swipe`
Perform a drag / swipe gesture between two points.
- **Parameters**:
- `x1`, `y1` *(numbers)*: Start coordinates.
- `x2`, `y2` *(numbers)*: End coordinates.
- `duration` *(optional number, default: 300)*: Duration in milliseconds.
---
### 8. `android_type_text`
Type text into the currently focused input. Handles space encoding (`%s`) and shell character escaping.
- **Parameters**:
- `text` *(string)*: Text to type.
---
### 9. `android_press_key`
Press a hardware or navigation key.
- **Supported Keys**: `HOME`, `BACK`, `ENTER`, `TAB`, `ESC`, `DELETE`, `SPACE`, `VOLUME_UP`, `VOLUME_DOWN`, `POWER`, `APP_SWITCH`, `CAMERA`, etc.
- **Parameters**:
- `key` *(string)*: Key name or numeric keycode.
---
### 10. `android_scroll`
Directional scrolling calculated against actual screen dimensions.
- **Parameters**:
- `direction` *(string: `up` | `down` | `left` | `right`)*
- `amount` *(optional number)*: Scroll distance in pixels.
---
### 11. `android_launch_app`
Launch an application by its package name.
- **Parameters**:
- `packageName` *(string)*: e.g. `com.android.settings`, `com.google.android.youtube`.
- `activity` *(optional string)*: Specific activity name.
---
### 12. `android_current_app`
Inspect the currently focused foreground package and activity.
---
### 13. `android_execute_action` (Unified Computer-Use Tool)
Single unified action dispatcher supporting all actions: `tap`, `swipe`, `type`, `press_key`, `click_element`, `scroll`, `launch_app`.
```json
{
"action": "click_element",
"text": "Wi-Fi"
}
```
---
## ๐ค Recommended AI Workflow: Observe โ Reason โ Act โ Verify
```text
1. OBSERVE:
AI calls `android_screenshot` and `android_ui_dump`.
2. REASON:
AI inspects visual and UI structure to identify target elements.
3. ACT:
AI calls `android_click_element`, `android_type_text`, or `android_scroll`.
4. VERIFY:
AI captures another screenshot/dump to confirm desired state change.
```
---
## ๐งช Testing
Run the automated test suite:
```bash
npm test
```
Tests use Vitest and mock the ADB execution layer, allowing full unit verification without requiring a physical Android device attached during CI/CD.
---
## ๐ Security Best Practices
- **No Arbitrary Shell Execution**: The server does NOT expose raw `adb shell` execution tools.
- **Safe Process Invocation**: All commands use `child_process.execFile` with explicit argument arrays to prevent shell injection.
- **Input Sanitization**: Package names, keycodes, and coordinate parameters are strictly validated via Zod schemas and bounds checking.
- **Stderr Isolated Logging**: All logs are directed exclusively to `stderr` to maintain strict JSON-RPC protocol compliance on `stdout`.
---
## ๐ License
MIT
TDQS
Scored across 13 tools
Most tools have clearly distinct purposes, but android_tap, android_click_element, and android_execute_action overlap in interaction, differing only by abstraction level (raw coordinates, element-based, and high-level bundling). Descriptions help disambiguate these, so the overlap is minor.
All tools share the 'android_' prefix, which is good, but the naming pattern is inconsistent: some are bare nouns (screenshot, scroll), some are verb phrases (type_text, launch_app), and some are noun phrases (current_app, device_info). This mix of conventions is still readable but not fully predictable.
With 13 tools, the server is well-scoped for a mobile automation domain, offering both low-level gestures and high-level actions without redundancy. This count is appropriate and each tool earns its place.
The tool surface covers core UI automation: screen capture, interaction (tap, swipe, type, press, scroll), element discovery (ui_dump, find_element, click_element), and app control (launch_app, current_app). Missing advanced gestures like pinch or long-press, but these are not essential for typical agent tasks.