expo-android

MCP server for Android emulator automation via ADB.
Requirements
- Node 18+
- Android SDK platform-tools (adb) available
- Android emulator or device connected
Verify adb:
Install
Claude Desktop, one-click: download expo-android.mcpb from the latest release and drag it into Settings โ Extensions. You can leave both fields empty โ adb is auto-detected and the only connected device is used by default.
Via npm:
npm install -g @fndchagas/expo-android
npx -y @fndchagas/expo-android
Quickstart
- Start an emulator or connect a device.
- Run
doctor to validate adb + device selection.
- Use
inspect, tapElement, inputText, etc.
Example:
await client.callTool({ name: 'expo-android.doctor', arguments: {} });
await client.callTool({
name: 'expo-android.inspect',
arguments: { onlyInteractive: true, maxElements: 200 },
});
Use with Claude Code CLI
claude mcp add expo-android \
--env ADB_PATH="$HOME/Library/Android/sdk/platform-tools/adb" \
--env ADB_SERIAL="auto" \
-- npx -y @fndchagas/expo-android
Use with OpenAI Codex CLI
codex mcp add expo-android \
--env ADB_PATH="$HOME/Library/Android/sdk/platform-tools/adb" \
--env ADB_SERIAL="auto" \
-- npx -y @fndchagas/expo-android
Or edit ~/.codex/config.toml:
[mcp_servers.expo-android]
command = "npx"
args = ["-y", "@fndchagas/expo-android"]
env = { ADB_PATH = "/Users/you/Library/Android/sdk/platform-tools/adb", ADB_SERIAL = "emulator-5554" }
Serial selection priority:
serial param (per tool call) โ setDevice override โ ADB_SERIAL env โ auto (if only one device).
Environment variables
| Variable | Default | Description |
|---|
ADB_PATH | adb | Path to adb executable |
ADB_SERIAL | optional | Device serial to target (auto to clear and auto-detect) |
ADB_TIMEOUT_MS | 15000 | Timeout for adb commands |
ADB_MAX_BUFFER_MB | 10 | Max output buffer size |
ADB_DEBUG | 0 | Log adb diagnostics to stderr |
MCP_TRANSPORT | stdio | Transport: stdio, http, or both |
PORT | 7332 | HTTP port when using http/both |
Troubleshooting
adb not found (spawn adb ENOENT)
The server starts even when adb is missing โ tools return the ADB executable not found
error until adb becomes reachable (run doctor to diagnose). To fix it, set ADB_PATH
or export an SDK path:
export ADB_PATH="$HOME/Library/Android/sdk/platform-tools/adb"
export ANDROID_HOME="$HOME/Library/Android/sdk"
If multiple devices are connected, set ADB_SERIAL to the target device.
You can also run setDevice at runtime:
await client.callTool({
name: 'expo-android.setDevice',
arguments: { serial: 'emulator-5554' },
});
If you update PATH or SDK variables, restart the MCP process so it can pick up
the new environment.
Tests
Tool names are plain identifiers (e.g. tap); your MCP client prefixes them with the server name you registered.
devices โ list connected devices and emulators.
doctor โ validate adb availability and show connected devices.
setDevice โ override the active device serial for this MCP process.
inspect โ UI dump parsed into elements with a summary (screenshot optional).
screenshot โ capture a screenshot only (base64 or file path).
findElement โ return elements that match search criteria.
tapElement โ find an element and tap its center.
waitForElement โ wait until an element appears (optionally with state checks).
assertElement โ verify element existence and state.
tap โ tap at x/y coordinates.
swipe โ swipe between coordinates.
longPress โ press and hold at coordinates.
inputText โ type text in the focused field.
keyEvent โ send Android key events (e.g., BACK, HOME).
openApp โ launch an app by package name.
listPackages โ list installed package names.
installExpoGo โ download the pinned Expo Go APK and install it via adb install -r (the url override only accepts official github.com/expo/expo-go-releases URLs).
Every tool declares MCP annotations (readOnlyHint/destructiveHint), so clients can auto-approve inspection tools and gate the ones that drive the device.
Search criteria
These tools accept flexible search inputs: findElement, tapElement,
waitForElement, assertElement.
Common fields:
text, textContains
contentDesc, contentDescContains
resourceId, resourceIdContains
class
normalizeWhitespace, caseInsensitive
MCP usage examples
Inspect
const result = await client.callTool({
name: 'expo-android.inspect',
arguments: { onlyInteractive: true, includeScreenshot: false, maxElements: 200 },
});
Inspect options:
includeScreenshot (default: false)
screenshotMode: base64 or path
screenshotPath: optional file path when using path
maxElements: limit elements returned
includeElements: return elements or summary only
Doctor
await client.callTool({
name: 'expo-android.doctor',
arguments: {},
});
Override serial per call
await client.callTool({
name: 'expo-android.tapElement',
arguments: { text: 'Search', serial: 'emulator-5554' },
});
Tap element
await client.callTool({
name: 'expo-android.tapElement',
arguments: { text: 'Private account' },
});
Wait + assert
await client.callTool({
name: 'expo-android.waitForElement',
arguments: { text: 'Save', timeout: 10000, shouldBeClickable: true },
});
await client.callTool({
name: 'expo-android.assertElement',
arguments: { text: 'Private account', shouldBeChecked: true },
});