mcadb 0.3.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
mcadb-0.3.1/.gitignore ADDED
@@ -0,0 +1,69 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ *.egg-info/
20
+ .installed.cfg
21
+ *.egg
22
+ MANIFEST
23
+
24
+ # Virtual environments
25
+ .env
26
+ .venv
27
+ env/
28
+ venv/
29
+ ENV/
30
+ env.bak/
31
+ venv.bak/
32
+
33
+ # IDE
34
+ .vscode/
35
+ .idea/
36
+ *.swp
37
+ *.swo
38
+ *~
39
+
40
+ # OS
41
+ .DS_Store
42
+ .DS_Store?
43
+ ._*
44
+ .Spotlight-V100
45
+ .Trashes
46
+ ehthumbs.db
47
+ Thumbs.db
48
+
49
+ # Testing
50
+ .coverage
51
+ .pytest_cache/
52
+ htmlcov/
53
+ .tox/
54
+
55
+ # Linting
56
+ .ruff_cache/
57
+ .mypy_cache/
58
+
59
+ # Screenshots and recordings
60
+ *.png
61
+ *.jpg
62
+ *.jpeg
63
+ *.mp4
64
+
65
+ # Docker
66
+ .dockerignore
67
+
68
+ # uv
69
+ .uv/
mcadb-0.3.1/CLAUDE.md ADDED
@@ -0,0 +1,74 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project Overview
6
+
7
+ mcadb - A FastMCP server exposing Android Debug Bridge (ADB) functionality through the Model Context Protocol. Enables AI assistants to automate Android devices via screenshots, input simulation, app control, UI inspection, file transfer, and shell commands.
8
+
9
+ ## Commands
10
+
11
+ ```bash
12
+ # Install dependencies
13
+ uv sync
14
+
15
+ # Run the server locally
16
+ uv run mcadb
17
+
18
+ # Run directly with uvx (no install needed)
19
+ uvx mcadb
20
+
21
+ # Development dependencies
22
+ uv sync --group dev
23
+
24
+ # Linting and formatting
25
+ uv run ruff check src/
26
+ uv run ruff format src/
27
+
28
+ # Type checking
29
+ uv run mypy src/
30
+
31
+ # Docker (requires privileged mode for USB access)
32
+ docker compose up --build
33
+ ```
34
+
35
+ ## Architecture
36
+
37
+ Modular MCPMixin architecture with 50 tools across 6 domain mixins:
38
+
39
+ - **`src/server.py`**: FastMCP app and `ADBServer` class (thin orchestrator inheriting all mixins)
40
+ - **`src/config.py`**: Persistent singleton config (`~/.config/adb-mcp/config.json`)
41
+ - **`src/models.py`**: Pydantic models (`DeviceInfo`, `CommandResult`, `ScreenshotResult`)
42
+ - **`src/mixins/base.py`**: Core ADB execution with `run_adb()`, `run_shell()`, and injection-safe `run_shell_args()` using `shlex.quote()`
43
+ - **`src/mixins/devices.py`**: Device discovery, info, logcat, reboot
44
+ - **`src/mixins/input.py`**: Tap, swipe, scroll, keys, text, clipboard, shell command
45
+ - **`src/mixins/apps.py`**: Launch, close, install, intents, broadcasts
46
+ - **`src/mixins/screenshot.py`**: Screen capture, recording, display settings
47
+ - **`src/mixins/ui.py`**: Accessibility tree dump, element search, text polling
48
+ - **`src/mixins/files.py`**: Push, pull, list, delete, exists
49
+
50
+ ### Key Patterns
51
+
52
+ - All tools use `run_shell_args()` (injection-safe) except `shell_command` which intentionally uses `run_shell()` for raw commands
53
+ - Developer mode tools are gated by `is_developer_mode()` checks and tagged with `tags={"developer"}`
54
+ - Destructive operations use `ctx.elicit()` for user confirmation
55
+ - `@mcp_tool()` and `@mcp_resource()` decorators from `fastmcp.contrib.mcp_mixin`
56
+
57
+ ## MCP Client Configuration
58
+
59
+ ```json
60
+ {
61
+ "mcpServers": {
62
+ "mcadb": {
63
+ "command": "uvx",
64
+ "args": ["mcadb"]
65
+ }
66
+ }
67
+ }
68
+ ```
69
+
70
+ ## Device Requirements
71
+
72
+ - ADB installed and accessible in PATH
73
+ - USB debugging enabled on Android device
74
+ - For Docker: `--privileged` flag and `/dev/bus/usb` volume mount required
mcadb-0.3.1/Dockerfile ADDED
@@ -0,0 +1,28 @@
1
+ FROM python:3.11-slim
2
+
3
+ # Install system dependencies including ADB
4
+ RUN apt-get update && apt-get install -y \
5
+ android-tools-adb \
6
+ android-tools-fastboot \
7
+ usbutils \
8
+ && rm -rf /var/lib/apt/lists/*
9
+
10
+ # Install uv
11
+ COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv
12
+
13
+ # Set working directory
14
+ WORKDIR /app
15
+
16
+ # Copy project files
17
+ COPY pyproject.toml uv.lock* ./
18
+
19
+ # Install dependencies
20
+ RUN uv sync --frozen
21
+
22
+ # Copy source code
23
+ COPY src/ ./src/
24
+
25
+ # Expose ADB server port (optional, mainly for debugging)
26
+ EXPOSE 5037
27
+
28
+ CMD ["uv", "run", "mcadb"]
mcadb-0.3.1/PKG-INFO ADDED
@@ -0,0 +1,275 @@
1
+ Metadata-Version: 2.4
2
+ Name: mcadb
3
+ Version: 0.3.1
4
+ Summary: Android ADB MCP Server for device automation via Model Context Protocol
5
+ Project-URL: Homepage, https://git.supported.systems/MCP/mcp-adb
6
+ Project-URL: Documentation, https://git.supported.systems/MCP/mcp-adb#readme
7
+ Project-URL: Repository, https://git.supported.systems/MCP/mcp-adb
8
+ Author-email: Ryan Malloy <ryan@supported.systems>
9
+ License: MIT
10
+ Keywords: adb,android,automation,fastmcp,mcp
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Software Development :: Testing
19
+ Classifier: Topic :: System :: Hardware :: Hardware Drivers
20
+ Requires-Python: >=3.11
21
+ Requires-Dist: fastmcp<3.0.0,>=2.14.0
22
+ Requires-Dist: pydantic>=2.12.0
23
+ Description-Content-Type: text/markdown
24
+
25
+ # mcadb
26
+
27
+ A [Model Context Protocol](https://modelcontextprotocol.io/) 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 &mdash; all through structured, type-safe tool calls.
28
+
29
+ Built on [FastMCP](https://gofastmcp.com/) with a modular mixin architecture. 50 tools across 6 domains. Tested on real hardware.
30
+
31
+ ## Quick Start
32
+
33
+ ```bash
34
+ # Run directly (no install)
35
+ uvx mcadb
36
+
37
+ # Or install and run
38
+ uv add mcadb
39
+ mcadb
40
+ ```
41
+
42
+ ### MCP Client Configuration
43
+
44
+ Add to your MCP client's config (Claude Desktop, Claude Code, etc.):
45
+
46
+ ```json
47
+ {
48
+ "mcpServers": {
49
+ "mcadb": {
50
+ "command": "uvx",
51
+ "args": ["mcadb"]
52
+ }
53
+ }
54
+ }
55
+ ```
56
+
57
+ For Claude Code:
58
+ ```bash
59
+ claude mcp add mcadb -- uvx mcadb
60
+ ```
61
+
62
+ For local development:
63
+ ```bash
64
+ claude mcp add mcadb -- uv run --directory /path/to/mcp-adb mcadb
65
+ ```
66
+
67
+ ## Prerequisites
68
+
69
+ - **Python 3.11+**
70
+ - **ADB** installed and on `PATH` (`adb devices` should work)
71
+ - **USB debugging** enabled on the Android device
72
+ - Device connected via USB (or `adb connect` for network)
73
+
74
+ ## What Can It Do?
75
+
76
+ ### Standard Tools (always available)
77
+
78
+ | Domain | Tool | What it does |
79
+ |--------|------|-------------|
80
+ | **Devices** | `devices_list` | Discover connected devices (USB + network) |
81
+ | | `devices_use` | Set active device for multi-device setups |
82
+ | | `devices_current` | Show which device is selected |
83
+ | | `device_info` | Battery, WiFi, storage, Android version, model |
84
+ | **Input** | `input_tap` | Tap at screen coordinates |
85
+ | | `input_swipe` | Swipe between two points |
86
+ | | `input_scroll_down` | Scroll down (auto-detects screen size) |
87
+ | | `input_scroll_up` | Scroll up (auto-detects screen size) |
88
+ | | `input_back` | Press Back |
89
+ | | `input_home` | Press Home |
90
+ | | `input_recent_apps` | Open app switcher |
91
+ | | `input_key` | Send any key event (`VOLUME_UP`, `ENTER`, etc.) |
92
+ | | `input_text` | Type text into focused field |
93
+ | | `clipboard_set` | Set clipboard (handles special chars), optional auto-paste |
94
+ | **Apps** | `app_launch` | Launch app by package name |
95
+ | | `app_open_url` | Open URL in default browser |
96
+ | | `app_close` | Force stop an app |
97
+ | | `app_current` | Get the foreground app and activity |
98
+ | **Screen** | `screenshot` | Capture screen as PNG |
99
+ | | `screen_size` | Get display resolution |
100
+ | | `screen_density` | Get display DPI |
101
+ | | `screen_on` / `screen_off` | Wake or sleep the display |
102
+ | **UI** | `ui_dump` | Dump accessibility tree (all visible elements) |
103
+ | | `ui_find_element` | Search for elements by text, ID, class, or description |
104
+ | | `wait_for_text` | Poll until text appears on screen |
105
+ | | `wait_for_text_gone` | Poll until text disappears |
106
+ | | `tap_text` | Find an element by text and tap it |
107
+ | **Config** | `config_status` | Show current settings |
108
+ | | `config_set_developer_mode` | Toggle developer tools |
109
+ | | `config_set_screenshot_dir` | Set where screenshots are saved |
110
+
111
+ ### Developer Mode Tools
112
+
113
+ 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.
114
+
115
+ | Domain | Tool | What it does |
116
+ |--------|------|-------------|
117
+ | **Shell** | `shell_command` | Run any shell command on device |
118
+ | **Input** | `input_long_press` | Press and hold gesture |
119
+ | **Apps** | `app_list_packages` | List installed packages (with filters) |
120
+ | | `app_install` | Install APK from host |
121
+ | | `app_uninstall` | Remove an app (with confirmation) |
122
+ | | `app_clear_data` | Wipe app data (with confirmation) |
123
+ | | `activity_start` | Launch activity with full intent control |
124
+ | | `broadcast_send` | Send broadcast intents |
125
+ | **Screen** | `screen_record` | Record screen to MP4 |
126
+ | | `screen_set_size` | Override display resolution |
127
+ | | `screen_reset_size` | Restore original resolution |
128
+ | **Device** | `device_reboot` | Reboot device (with confirmation) |
129
+ | | `logcat_capture` | Capture system logs |
130
+ | | `logcat_clear` | Clear log buffer |
131
+ | **Files** | `file_push` | Transfer file to device |
132
+ | | `file_pull` | Transfer file from device |
133
+ | | `file_list` | List directory contents |
134
+ | | `file_delete` | Delete file (with confirmation) |
135
+ | | `file_exists` | Check if file exists |
136
+
137
+ ### Resources
138
+
139
+ | URI | Description |
140
+ |-----|-------------|
141
+ | `adb://devices` | Connected device list |
142
+ | `adb://device/{id}` | Detailed device properties |
143
+ | `adb://apps/current` | Currently focused app |
144
+ | `adb://screen/info` | Screen resolution and DPI |
145
+ | `adb://help` | Tool reference and tips |
146
+
147
+ ## Usage Examples
148
+
149
+ **Screenshot + UI inspection loop** (how an AI assistant typically navigates):
150
+ ```
151
+ 1. screenshot() → See what's on screen
152
+ 2. ui_dump() → Get element tree with tap coordinates
153
+ 3. tap_text("Settings") → Tap the "Settings" element
154
+ 4. wait_for_text("Wi-Fi") → Wait for the screen to load
155
+ 5. screenshot() → Verify the result
156
+ ```
157
+
158
+ **Open a URL and check what loaded:**
159
+ ```
160
+ 1. app_open_url("https://example.com")
161
+ 2. wait_for_text("Example Domain")
162
+ 3. screenshot()
163
+ ```
164
+
165
+ **Install and launch an APK** (developer mode):
166
+ ```
167
+ 1. config_set_developer_mode(true)
168
+ 2. app_install("/path/to/app.apk")
169
+ 3. app_launch("com.example.myapp")
170
+ 4. logcat_capture(filter_spec="MyApp:D *:S")
171
+ ```
172
+
173
+ **Multi-device workflow:**
174
+ ```
175
+ 1. devices_list() → See all connected devices
176
+ 2. devices_use("SERIAL_NUMBER") → Select target device
177
+ 3. device_info() → Check battery, WiFi, storage
178
+ 4. screenshot() → Capture from selected device
179
+ ```
180
+
181
+ ## Architecture
182
+
183
+ The server uses FastMCP's [MCPMixin](https://gofastmcp.com/) pattern to organize 50 tools into focused, single-responsibility modules:
184
+
185
+ ```
186
+ src/
187
+ server.py ← FastMCP app, ADBServer (thin orchestrator)
188
+ config.py ← Persistent config (~/.config/adb-mcp/config.json)
189
+ models.py ← Pydantic models (DeviceInfo, CommandResult, ScreenshotResult)
190
+ mixins/
191
+ base.py ← ADB command execution, injection-safe shell quoting
192
+ devices.py ← Device discovery, info, logcat, reboot
193
+ input.py ← Tap, swipe, scroll, keys, text, clipboard, shell
194
+ apps.py ← Launch, close, install, intents, broadcasts
195
+ screenshot.py ← Capture, recording, display settings
196
+ ui.py ← Accessibility tree, element search, text polling
197
+ files.py ← Push, pull, list, delete, exists
198
+ ```
199
+
200
+ `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.
201
+
202
+ ## Security Model
203
+
204
+ All tools that accept user-provided values use **injection-safe command execution**:
205
+
206
+ - **`run_shell_args()`** quotes every argument with `shlex.quote()` before sending to the device shell. This is the default for all tools.
207
+ - **`run_shell()`** (string form) is only used by the developer-mode `shell_command` tool, where the user intentionally provides a raw command.
208
+ - **`input_text()`** rejects special characters (`$ ( ) ; | & < >` etc.) and directs users to `clipboard_set()` instead.
209
+ - **`input_key()`** strips non-alphanumeric characters from key codes.
210
+ - **Destructive operations** (uninstall, clear data, delete, reboot) require user confirmation via MCP elicitation.
211
+ - **Developer mode** is off by default and must be explicitly enabled. Settings persist at `~/.config/adb-mcp/config.json`.
212
+
213
+ ## Docker
214
+
215
+ ```bash
216
+ docker build -t mcadb .
217
+ docker run --privileged -v /dev/bus/usb:/dev/bus/usb mcadb
218
+ ```
219
+
220
+ The `--privileged` flag and USB volume mount are required for ADB to detect physical devices.
221
+
222
+ MCP client config for Docker:
223
+ ```json
224
+ {
225
+ "mcpServers": {
226
+ "mcadb": {
227
+ "command": "docker",
228
+ "args": ["run", "-i", "--privileged", "-v", "/dev/bus/usb:/dev/bus/usb", "mcadb"]
229
+ }
230
+ }
231
+ }
232
+ ```
233
+
234
+ ## Development
235
+
236
+ ```bash
237
+ # Clone and install
238
+ git clone https://git.supported.systems/MCP/mcp-adb.git
239
+ cd mcp-adb
240
+ uv sync --group dev
241
+
242
+ # Run locally
243
+ uv run mcadb
244
+
245
+ # Lint
246
+ uv run ruff check src/
247
+
248
+ # Format
249
+ uv run ruff format src/
250
+
251
+ # Type check
252
+ uv run mypy src/
253
+ ```
254
+
255
+ ## Configuration
256
+
257
+ Settings are stored at `~/.config/adb-mcp/config.json` (override with `ADB_MCP_CONFIG_DIR` env var):
258
+
259
+ ```json
260
+ {
261
+ "developer_mode": false,
262
+ "default_screenshot_dir": null,
263
+ "auto_select_single_device": true
264
+ }
265
+ ```
266
+
267
+ | Setting | Default | Description |
268
+ |---------|---------|-------------|
269
+ | `developer_mode` | `false` | Unlock advanced tools (shell, install, reboot, etc.) |
270
+ | `default_screenshot_dir` | `null` | Directory for screenshots/recordings (null = cwd) |
271
+ | `auto_select_single_device` | `true` | Skip device selection when only one is connected |
272
+
273
+ ## License
274
+
275
+ MIT
mcadb-0.3.1/README.md ADDED
@@ -0,0 +1,251 @@
1
+ # mcadb
2
+
3
+ A [Model Context Protocol](https://modelcontextprotocol.io/) 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 &mdash; all through structured, type-safe tool calls.
4
+
5
+ Built on [FastMCP](https://gofastmcp.com/) with a modular mixin architecture. 50 tools across 6 domains. Tested on real hardware.
6
+
7
+ ## Quick Start
8
+
9
+ ```bash
10
+ # Run directly (no install)
11
+ uvx mcadb
12
+
13
+ # Or install and run
14
+ uv add mcadb
15
+ mcadb
16
+ ```
17
+
18
+ ### MCP Client Configuration
19
+
20
+ Add to your MCP client's config (Claude Desktop, Claude Code, etc.):
21
+
22
+ ```json
23
+ {
24
+ "mcpServers": {
25
+ "mcadb": {
26
+ "command": "uvx",
27
+ "args": ["mcadb"]
28
+ }
29
+ }
30
+ }
31
+ ```
32
+
33
+ For Claude Code:
34
+ ```bash
35
+ claude mcp add mcadb -- uvx mcadb
36
+ ```
37
+
38
+ For local development:
39
+ ```bash
40
+ claude mcp add mcadb -- uv run --directory /path/to/mcp-adb mcadb
41
+ ```
42
+
43
+ ## Prerequisites
44
+
45
+ - **Python 3.11+**
46
+ - **ADB** installed and on `PATH` (`adb devices` should work)
47
+ - **USB debugging** enabled on the Android device
48
+ - Device connected via USB (or `adb connect` for network)
49
+
50
+ ## What Can It Do?
51
+
52
+ ### Standard Tools (always available)
53
+
54
+ | Domain | Tool | What it does |
55
+ |--------|------|-------------|
56
+ | **Devices** | `devices_list` | Discover connected devices (USB + network) |
57
+ | | `devices_use` | Set active device for multi-device setups |
58
+ | | `devices_current` | Show which device is selected |
59
+ | | `device_info` | Battery, WiFi, storage, Android version, model |
60
+ | **Input** | `input_tap` | Tap at screen coordinates |
61
+ | | `input_swipe` | Swipe between two points |
62
+ | | `input_scroll_down` | Scroll down (auto-detects screen size) |
63
+ | | `input_scroll_up` | Scroll up (auto-detects screen size) |
64
+ | | `input_back` | Press Back |
65
+ | | `input_home` | Press Home |
66
+ | | `input_recent_apps` | Open app switcher |
67
+ | | `input_key` | Send any key event (`VOLUME_UP`, `ENTER`, etc.) |
68
+ | | `input_text` | Type text into focused field |
69
+ | | `clipboard_set` | Set clipboard (handles special chars), optional auto-paste |
70
+ | **Apps** | `app_launch` | Launch app by package name |
71
+ | | `app_open_url` | Open URL in default browser |
72
+ | | `app_close` | Force stop an app |
73
+ | | `app_current` | Get the foreground app and activity |
74
+ | **Screen** | `screenshot` | Capture screen as PNG |
75
+ | | `screen_size` | Get display resolution |
76
+ | | `screen_density` | Get display DPI |
77
+ | | `screen_on` / `screen_off` | Wake or sleep the display |
78
+ | **UI** | `ui_dump` | Dump accessibility tree (all visible elements) |
79
+ | | `ui_find_element` | Search for elements by text, ID, class, or description |
80
+ | | `wait_for_text` | Poll until text appears on screen |
81
+ | | `wait_for_text_gone` | Poll until text disappears |
82
+ | | `tap_text` | Find an element by text and tap it |
83
+ | **Config** | `config_status` | Show current settings |
84
+ | | `config_set_developer_mode` | Toggle developer tools |
85
+ | | `config_set_screenshot_dir` | Set where screenshots are saved |
86
+
87
+ ### Developer Mode Tools
88
+
89
+ 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.
90
+
91
+ | Domain | Tool | What it does |
92
+ |--------|------|-------------|
93
+ | **Shell** | `shell_command` | Run any shell command on device |
94
+ | **Input** | `input_long_press` | Press and hold gesture |
95
+ | **Apps** | `app_list_packages` | List installed packages (with filters) |
96
+ | | `app_install` | Install APK from host |
97
+ | | `app_uninstall` | Remove an app (with confirmation) |
98
+ | | `app_clear_data` | Wipe app data (with confirmation) |
99
+ | | `activity_start` | Launch activity with full intent control |
100
+ | | `broadcast_send` | Send broadcast intents |
101
+ | **Screen** | `screen_record` | Record screen to MP4 |
102
+ | | `screen_set_size` | Override display resolution |
103
+ | | `screen_reset_size` | Restore original resolution |
104
+ | **Device** | `device_reboot` | Reboot device (with confirmation) |
105
+ | | `logcat_capture` | Capture system logs |
106
+ | | `logcat_clear` | Clear log buffer |
107
+ | **Files** | `file_push` | Transfer file to device |
108
+ | | `file_pull` | Transfer file from device |
109
+ | | `file_list` | List directory contents |
110
+ | | `file_delete` | Delete file (with confirmation) |
111
+ | | `file_exists` | Check if file exists |
112
+
113
+ ### Resources
114
+
115
+ | URI | Description |
116
+ |-----|-------------|
117
+ | `adb://devices` | Connected device list |
118
+ | `adb://device/{id}` | Detailed device properties |
119
+ | `adb://apps/current` | Currently focused app |
120
+ | `adb://screen/info` | Screen resolution and DPI |
121
+ | `adb://help` | Tool reference and tips |
122
+
123
+ ## Usage Examples
124
+
125
+ **Screenshot + UI inspection loop** (how an AI assistant typically navigates):
126
+ ```
127
+ 1. screenshot() → See what's on screen
128
+ 2. ui_dump() → Get element tree with tap coordinates
129
+ 3. tap_text("Settings") → Tap the "Settings" element
130
+ 4. wait_for_text("Wi-Fi") → Wait for the screen to load
131
+ 5. screenshot() → Verify the result
132
+ ```
133
+
134
+ **Open a URL and check what loaded:**
135
+ ```
136
+ 1. app_open_url("https://example.com")
137
+ 2. wait_for_text("Example Domain")
138
+ 3. screenshot()
139
+ ```
140
+
141
+ **Install and launch an APK** (developer mode):
142
+ ```
143
+ 1. config_set_developer_mode(true)
144
+ 2. app_install("/path/to/app.apk")
145
+ 3. app_launch("com.example.myapp")
146
+ 4. logcat_capture(filter_spec="MyApp:D *:S")
147
+ ```
148
+
149
+ **Multi-device workflow:**
150
+ ```
151
+ 1. devices_list() → See all connected devices
152
+ 2. devices_use("SERIAL_NUMBER") → Select target device
153
+ 3. device_info() → Check battery, WiFi, storage
154
+ 4. screenshot() → Capture from selected device
155
+ ```
156
+
157
+ ## Architecture
158
+
159
+ The server uses FastMCP's [MCPMixin](https://gofastmcp.com/) pattern to organize 50 tools into focused, single-responsibility modules:
160
+
161
+ ```
162
+ src/
163
+ server.py ← FastMCP app, ADBServer (thin orchestrator)
164
+ config.py ← Persistent config (~/.config/adb-mcp/config.json)
165
+ models.py ← Pydantic models (DeviceInfo, CommandResult, ScreenshotResult)
166
+ mixins/
167
+ base.py ← ADB command execution, injection-safe shell quoting
168
+ devices.py ← Device discovery, info, logcat, reboot
169
+ input.py ← Tap, swipe, scroll, keys, text, clipboard, shell
170
+ apps.py ← Launch, close, install, intents, broadcasts
171
+ screenshot.py ← Capture, recording, display settings
172
+ ui.py ← Accessibility tree, element search, text polling
173
+ files.py ← Push, pull, list, delete, exists
174
+ ```
175
+
176
+ `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.
177
+
178
+ ## Security Model
179
+
180
+ All tools that accept user-provided values use **injection-safe command execution**:
181
+
182
+ - **`run_shell_args()`** quotes every argument with `shlex.quote()` before sending to the device shell. This is the default for all tools.
183
+ - **`run_shell()`** (string form) is only used by the developer-mode `shell_command` tool, where the user intentionally provides a raw command.
184
+ - **`input_text()`** rejects special characters (`$ ( ) ; | & < >` etc.) and directs users to `clipboard_set()` instead.
185
+ - **`input_key()`** strips non-alphanumeric characters from key codes.
186
+ - **Destructive operations** (uninstall, clear data, delete, reboot) require user confirmation via MCP elicitation.
187
+ - **Developer mode** is off by default and must be explicitly enabled. Settings persist at `~/.config/adb-mcp/config.json`.
188
+
189
+ ## Docker
190
+
191
+ ```bash
192
+ docker build -t mcadb .
193
+ docker run --privileged -v /dev/bus/usb:/dev/bus/usb mcadb
194
+ ```
195
+
196
+ The `--privileged` flag and USB volume mount are required for ADB to detect physical devices.
197
+
198
+ MCP client config for Docker:
199
+ ```json
200
+ {
201
+ "mcpServers": {
202
+ "mcadb": {
203
+ "command": "docker",
204
+ "args": ["run", "-i", "--privileged", "-v", "/dev/bus/usb:/dev/bus/usb", "mcadb"]
205
+ }
206
+ }
207
+ }
208
+ ```
209
+
210
+ ## Development
211
+
212
+ ```bash
213
+ # Clone and install
214
+ git clone https://git.supported.systems/MCP/mcp-adb.git
215
+ cd mcp-adb
216
+ uv sync --group dev
217
+
218
+ # Run locally
219
+ uv run mcadb
220
+
221
+ # Lint
222
+ uv run ruff check src/
223
+
224
+ # Format
225
+ uv run ruff format src/
226
+
227
+ # Type check
228
+ uv run mypy src/
229
+ ```
230
+
231
+ ## Configuration
232
+
233
+ Settings are stored at `~/.config/adb-mcp/config.json` (override with `ADB_MCP_CONFIG_DIR` env var):
234
+
235
+ ```json
236
+ {
237
+ "developer_mode": false,
238
+ "default_screenshot_dir": null,
239
+ "auto_select_single_device": true
240
+ }
241
+ ```
242
+
243
+ | Setting | Default | Description |
244
+ |---------|---------|-------------|
245
+ | `developer_mode` | `false` | Unlock advanced tools (shell, install, reboot, etc.) |
246
+ | `default_screenshot_dir` | `null` | Directory for screenshots/recordings (null = cwd) |
247
+ | `auto_select_single_device` | `true` | Skip device selection when only one is connected |
248
+
249
+ ## License
250
+
251
+ MIT