Android ADB MCP Server for device automation via Model Context Protocol
Project description
mcadb
A Model Context Protocol server that gives AI assistants direct control over Android devices through ADB. Point any MCP-compatible client at a phone plugged into USB, and it can take screenshots, tap buttons, launch apps, inspect UI elements, transfer files, and run shell commands — all through structured, type-safe tool calls.
Built on FastMCP with a modular mixin architecture. 50 tools across 6 domains. Tested on real hardware.
Quick Start
# Run directly (no install)
uvx mcadb
# Or install and run
uv add mcadb
mcadb
MCP Client Configuration
Add to your MCP client's config (Claude Desktop, Claude Code, etc.):
{
"mcpServers": {
"mcadb": {
"command": "uvx",
"args": ["mcadb"]
}
}
}
For Claude Code:
claude mcp add mcadb -- uvx mcadb
For local development:
claude mcp add mcadb -- uv run --directory /path/to/mcp-adb mcadb
Prerequisites
- Python 3.11+
- ADB installed and on
PATH(adb devicesshould work) - USB debugging enabled on the Android device
- Device connected via USB (or
adb connectfor network)
What Can It Do?
Standard Tools (always available)
| Domain | Tool | What it does |
|---|---|---|
| Devices | devices_list |
Discover connected devices (USB + network) |
devices_use |
Set active device for multi-device setups | |
devices_current |
Show which device is selected | |
device_info |
Battery, WiFi, storage, Android version, model | |
| Input | input_tap |
Tap at screen coordinates |
input_swipe |
Swipe between two points | |
input_scroll_down |
Scroll down (auto-detects screen size) | |
input_scroll_up |
Scroll up (auto-detects screen size) | |
input_back |
Press Back | |
input_home |
Press Home | |
input_recent_apps |
Open app switcher | |
input_key |
Send any key event (VOLUME_UP, ENTER, etc.) |
|
input_text |
Type text into focused field | |
clipboard_set |
Set clipboard (handles special chars), optional auto-paste | |
| Apps | app_launch |
Launch app by package name |
app_open_url |
Open URL in default browser | |
app_close |
Force stop an app | |
app_current |
Get the foreground app and activity | |
| Screen | screenshot |
Capture screen as PNG |
screen_size |
Get display resolution | |
screen_density |
Get display DPI | |
screen_on / screen_off |
Wake or sleep the display | |
| UI | ui_dump |
Dump accessibility tree (all visible elements) |
ui_find_element |
Search for elements by text, ID, class, or description | |
wait_for_text |
Poll until text appears on screen | |
wait_for_text_gone |
Poll until text disappears | |
tap_text |
Find an element by text and tap it | |
| Config | config_status |
Show current settings |
config_set_developer_mode |
Toggle developer tools | |
config_set_screenshot_dir |
Set where screenshots are saved |
Developer Mode Tools
Enable with config_set_developer_mode(true) to unlock power-user tools. Destructive operations (uninstall, clear data, reboot, delete) require user confirmation via MCP elicitation.
| Domain | Tool | What it does |
|---|---|---|
| Shell | shell_command |
Run any shell command on device |
| Input | input_long_press |
Press and hold gesture |
| Apps | app_list_packages |
List installed packages (with filters) |
app_install |
Install APK from host | |
app_uninstall |
Remove an app (with confirmation) | |
app_clear_data |
Wipe app data (with confirmation) | |
activity_start |
Launch activity with full intent control | |
broadcast_send |
Send broadcast intents | |
| Screen | screen_record |
Record screen to MP4 |
screen_set_size |
Override display resolution | |
screen_reset_size |
Restore original resolution | |
| Device | device_reboot |
Reboot device (with confirmation) |
logcat_capture |
Capture system logs | |
logcat_clear |
Clear log buffer | |
| Files | file_push |
Transfer file to device |
file_pull |
Transfer file from device | |
file_list |
List directory contents | |
file_delete |
Delete file (with confirmation) | |
file_exists |
Check if file exists |
Resources
| URI | Description |
|---|---|
adb://devices |
Connected device list |
adb://device/{id} |
Detailed device properties |
adb://apps/current |
Currently focused app |
adb://screen/info |
Screen resolution and DPI |
adb://help |
Tool reference and tips |
Usage Examples
Screenshot + UI inspection loop (how an AI assistant typically navigates):
1. screenshot() → See what's on screen
2. ui_dump() → Get element tree with tap coordinates
3. tap_text("Settings") → Tap the "Settings" element
4. wait_for_text("Wi-Fi") → Wait for the screen to load
5. screenshot() → Verify the result
Open a URL and check what loaded:
1. app_open_url("https://example.com")
2. wait_for_text("Example Domain")
3. screenshot()
Install and launch an APK (developer mode):
1. config_set_developer_mode(true)
2. app_install("/path/to/app.apk")
3. app_launch("com.example.myapp")
4. logcat_capture(filter_spec="MyApp:D *:S")
Multi-device workflow:
1. devices_list() → See all connected devices
2. devices_use("SERIAL_NUMBER") → Select target device
3. device_info() → Check battery, WiFi, storage
4. screenshot() → Capture from selected device
Architecture
The server uses FastMCP's MCPMixin pattern to organize 50 tools into focused, single-responsibility modules:
src/
server.py ← FastMCP app, ADBServer (thin orchestrator)
config.py ← Persistent config (~/.config/adb-mcp/config.json)
models.py ← Pydantic models (DeviceInfo, CommandResult, ScreenshotResult)
mixins/
base.py ← ADB command execution, injection-safe shell quoting
devices.py ← Device discovery, info, logcat, reboot
input.py ← Tap, swipe, scroll, keys, text, clipboard, shell
apps.py ← Launch, close, install, intents, broadcasts
screenshot.py ← Capture, recording, display settings
ui.py ← Accessibility tree, element search, text polling
files.py ← Push, pull, list, delete, exists
ADBServer inherits all six mixins. Each mixin calls run_shell_args() (injection-safe) or run_adb() on the base class. The base handles device targeting, subprocess execution, and timeouts.
Security Model
All tools that accept user-provided values use injection-safe command execution:
run_shell_args()quotes every argument withshlex.quote()before sending to the device shell. This is the default for all tools.run_shell()(string form) is only used by the developer-modeshell_commandtool, where the user intentionally provides a raw command.input_text()rejects special characters ($ ( ) ; | & < >etc.) and directs users toclipboard_set()instead.input_key()strips non-alphanumeric characters from key codes.- Destructive operations (uninstall, clear data, delete, reboot) require user confirmation via MCP elicitation.
- Developer mode is off by default and must be explicitly enabled. Settings persist at
~/.config/adb-mcp/config.json.
Docker
docker build -t mcadb .
docker run --privileged -v /dev/bus/usb:/dev/bus/usb mcadb
The --privileged flag and USB volume mount are required for ADB to detect physical devices.
MCP client config for Docker:
{
"mcpServers": {
"mcadb": {
"command": "docker",
"args": ["run", "-i", "--privileged", "-v", "/dev/bus/usb:/dev/bus/usb", "mcadb"]
}
}
}
Development
# Clone and install
git clone https://git.supported.systems/MCP/mcp-adb.git
cd mcp-adb
uv sync --group dev
# Run locally
uv run mcadb
# Lint
uv run ruff check src/
# Format
uv run ruff format src/
# Type check
uv run mypy src/
Configuration
Settings are stored at ~/.config/adb-mcp/config.json (override with ADB_MCP_CONFIG_DIR env var):
{
"developer_mode": false,
"default_screenshot_dir": null,
"auto_select_single_device": true
}
| Setting | Default | Description |
|---|---|---|
developer_mode |
false |
Unlock advanced tools (shell, install, reboot, etc.) |
default_screenshot_dir |
null |
Directory for screenshots/recordings (null = cwd) |
auto_select_single_device |
true |
Skip device selection when only one is connected |
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mcadb-0.3.1.tar.gz.
File metadata
- Download URL: mcadb-0.3.1.tar.gz
- Upload date:
- Size: 104.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"EndeavourOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c23d5d5688a7028156829e8f93b141edb445a776753f3fa6802e3e2c19a92351
|
|
| MD5 |
b0597f34342e694673a9deef09989266
|
|
| BLAKE2b-256 |
06f5fabf3cea908c976fc1af4c95018df01532ad499bfa88979a005e78959086
|
File details
Details for the file mcadb-0.3.1-py3-none-any.whl.
File metadata
- Download URL: mcadb-0.3.1-py3-none-any.whl
- Upload date:
- Size: 31.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"EndeavourOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
90ad5eb55395a0ea9deb264c24c9a2fa075789f2783f8b9e68a6bee0a6831952
|
|
| MD5 |
b563c29531fcfa24f732e3a0c261a68f
|
|
| BLAKE2b-256 |
8d705263df78b8559b8738d908eff709561e2d84f2e99057abc34f9c403fad1d
|