mobile-debug-mcp 0.4.0 → 0.6.0

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.
@@ -0,0 +1,33 @@
1
+ # Copilot Instructions for mobile-debug-mcp
2
+
3
+ ## Build and Run
4
+ - **Build**: `npm run build` (runs `tsc` to compile TypeScript to `dist/`)
5
+ - **Start**: `npm start` (runs the compiled server at `dist/server.js`)
6
+ - **Dev Workflow**: modify `src/*.ts` -> `npm run build` -> `npm start` to test changes.
7
+
8
+ ## Architecture
9
+ - **Core**: `src/server.ts` implements the MCP server using `@modelcontextprotocol/sdk`. It handles tool registration and execution.
10
+ - **Platform Modules**:
11
+ - `src/android.ts`: Encapsulates `adb` commands for Android device interaction.
12
+ - `src/ios.ts`: Encapsulates `xcrun simctl` commands for iOS simulator interaction.
13
+ - **Types**: `src/types.ts` defines shared interfaces for device info and tool responses.
14
+
15
+ ## Key Conventions
16
+
17
+ ### Tool Implementation
18
+ - **Response Format**: Tools typically return a list of content blocks.
19
+ - `start_app`: Returns a single text block containing JSON (via `wrapResponse`).
20
+ - `terminate_app`: Returns a single text block containing JSON (via `wrapResponse`).
21
+ - `restart_app`: Returns a single text block containing JSON (via `wrapResponse`).
22
+ - `reset_app_data`: Returns a single text block containing JSON (via `wrapResponse`).
23
+ - `get_logs`: Returns a text block (JSON metadata) AND a text block (raw logs).
24
+ - `capture_screenshot`: Returns a text block (JSON metadata) AND an image block (base64 PNG).
25
+ - **Metadata**: Always include a `device` object (platform, id, model, etc.) in the JSON response part.
26
+
27
+ ### External Tools
28
+ - **Android**: Uses `process.env.ADB_PATH` or defaults to `adb`.
29
+ - **iOS**: Uses `process.env.XCRUN_PATH` or defaults to `xcrun`. Assumes a booted simulator.
30
+ - **Execution**: Uses `child_process.exec` for running shell commands.
31
+
32
+ ### Error Handling
33
+ - Tools should catch execution errors and return a user-friendly error message in a `text` content block, rather than crashing the server.
package/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # Mobile Debug MCP
2
2
 
3
- **Mobile Debug MCP** is a minimal MCP server for AI-assisted mobile development. It allows you to **launch Android or iOS apps** and **read their logs** from an MCP-compatible AI client.
3
+ **Mobile Debug MCP** is a minimal, secure MCP server for AI-assisted mobile development. It allows you to **launch Android or iOS apps**, **read their logs**, and **inspect UI** from an MCP-compatible AI client.
4
+
5
+ This server is designed with security in mind, using strict argument handling to prevent shell injection, and reliability, with robust process management to avoid hanging operations.
6
+
7
+ > **Note:** iOS support is currently an untested Work In Progress (WIP). Please use with caution and report any issues.
4
8
 
5
9
  ---
6
10
 
@@ -9,6 +13,9 @@
9
13
  - Launch Android apps via package name.
10
14
  - Launch iOS apps via bundle ID on a booted simulator.
11
15
  - Fetch recent logs from Android or iOS apps.
16
+ - Terminate and restart apps.
17
+ - Clear app data for fresh installs.
18
+ - Capture screenshots.
12
19
  - Cross-platform support (Android + iOS).
13
20
  - Minimal, focused design for fast debugging loops.
14
21
 
@@ -19,13 +26,27 @@
19
26
  - Node.js >= 18
20
27
  - Android SDK (`adb` in PATH) for Android support
21
28
  - Xcode command-line tools (`xcrun simctl`) for iOS support
29
+ - **iOS Device Bridge (`idb`)** for iOS UI tree support
22
30
  - Booted iOS simulator for iOS testing
23
31
 
24
32
  ---
25
33
 
26
34
  ## Installation
27
35
 
28
- Clone the repo and build:
36
+ You can install and use **Mobile Debug MCP** in one of two ways:
37
+
38
+ ### 1. Install Dependencies
39
+
40
+ **iOS Prerequisite (`idb`):**
41
+ To use the `get_ui_tree` tool on iOS, you must install Facebook's `idb`:
42
+
43
+ ```bash
44
+ brew tap facebook/fb
45
+ brew install idb-companion
46
+ pip3 install fb-idb
47
+ ```
48
+
49
+ ### 2. Clone the repository for local development
29
50
 
30
51
  ```bash
31
52
  git clone https://github.com/YOUR_USERNAME/mobile-debug-mcp.git
@@ -34,74 +55,230 @@ npm install
34
55
  npm run build
35
56
  ```
36
57
 
37
- Alternatively, you can publish to npm and install globally:
58
+ This option is suitable if you want to modify or contribute to the code.
59
+
60
+ ### 3. Install via npm for standard use
38
61
 
39
62
  ```bash
40
63
  npm install -g mobile-debug-mcp
41
64
  ```
42
65
 
66
+ This option installs the package globally for easy use without cloning the repo.
67
+
43
68
  ---
44
69
 
45
70
  ## MCP Server Configuration
46
71
 
47
- Example WebUI MCP config:
72
+ Example WebUI MCP config using `npx --yes` and environment variables:
48
73
 
49
74
  ```json
50
75
  {
51
76
  "mcpServers": {
52
77
  "mobile-debug": {
53
- "command": "node",
54
- "args": ["/full/path/to/mobile-debug-mcp/dist/server.js"]
78
+ "command": "npx",
79
+ "args": [
80
+ "--yes",
81
+ "mobile-debug-mcp",
82
+ "server"
83
+ ],
84
+ "env": {
85
+ "ADB_PATH": "/path/to/adb",
86
+ "XCRUN_PATH": "/usr/bin/xcrun"
87
+ }
55
88
  }
56
89
  }
57
90
  }
58
91
  ```
59
92
 
60
- > Make sure to replace `/full/path/to/` with your actual project path.
93
+ > Make sure to set `ADB_PATH` (Android) and `XCRUN_PATH` (iOS) if the tools are not in your system PATH.
61
94
 
62
95
  ---
63
96
 
64
97
  ## Tools
65
98
 
99
+ All tools accept a JSON input payload and return a structured JSON response. **Every response includes a `device` object** (with information about the selected device/simulator used for the operation), plus the tool-specific output.
100
+
66
101
  ### start_app
67
102
  Launch a mobile app.
68
103
 
69
104
  **Input:**
105
+ ```jsonc
106
+ {
107
+ "platform": "android" | "ios",
108
+ "appId": "com.example.app", // Android package or iOS bundle ID (Required)
109
+ "deviceId": "emulator-5554" // Optional: target specific device/simulator
110
+ }
111
+ ```
70
112
 
113
+ **Response:**
71
114
  ```json
115
+ {
116
+ "device": { /* device info */ },
117
+ "appStarted": true,
118
+ "launchTimeMs": 123
119
+ }
120
+ ```
121
+
122
+ ### get_logs
123
+ Fetch recent logs from the app or device.
124
+
125
+ **Input:**
126
+ ```jsonc
72
127
  {
73
128
  "platform": "android" | "ios",
74
- "id": "com.example.app" // Android package or iOS bundle ID
129
+ "appId": "com.example.app", // Optional: filter logs by app
130
+ "deviceId": "emulator-5554", // Optional: target specific device
131
+ "lines": 200 // Optional: number of lines (Android only)
75
132
  }
76
133
  ```
77
134
 
78
- **Example:**
135
+ **Response:**
136
+ Returns two content blocks:
137
+ 1. JSON metadata:
138
+ ```json
139
+ {
140
+ "device": { /* device info */ },
141
+ "result": { "lines": 50, "crashLines": [...] }
142
+ }
143
+ ```
144
+ 2. Plain text log output.
145
+
146
+ ### capture_screenshot
147
+ Capture a screenshot of the current device screen.
148
+
149
+ **Input:**
150
+ ```jsonc
151
+ {
152
+ "platform": "android" | "ios",
153
+ "deviceId": "emulator-5554" // Optional: target specific device
154
+ }
155
+ ```
79
156
 
157
+ **Response:**
158
+ Returns two content blocks:
159
+ 1. JSON metadata:
80
160
  ```json
81
161
  {
82
- "platform": "android",
83
- "id": "com.modul8.app"
162
+ "device": { /* device info */ },
163
+ "result": { "resolution": { "width": 1080, "height": 1920 } }
84
164
  }
85
165
  ```
166
+ 2. Image content (image/png) containing the raw PNG data.
86
167
 
87
- ### get_logs
88
- Fetch recent logs from the app.
168
+ ### terminate_app
169
+ Terminate a running app.
170
+
171
+ **Input:**
172
+ ```jsonc
173
+ {
174
+ "platform": "android" | "ios",
175
+ "appId": "com.example.app", // Android package or iOS bundle ID (Required)
176
+ "deviceId": "emulator-5554" // Optional
177
+ }
178
+ ```
179
+
180
+ **Response:**
181
+ ```json
182
+ {
183
+ "device": { /* device info */ },
184
+ "appTerminated": true
185
+ }
186
+ ```
187
+
188
+ ### restart_app
189
+ Restart an app (terminate then launch).
190
+
191
+ **Input:**
192
+ ```jsonc
193
+ {
194
+ "platform": "android" | "ios",
195
+ "appId": "com.example.app", // Android package or iOS bundle ID (Required)
196
+ "deviceId": "emulator-5554" // Optional
197
+ }
198
+ ```
199
+
200
+ **Response:**
201
+ ```json
202
+ {
203
+ "device": { /* device info */ },
204
+ "appRestarted": true,
205
+ "launchTimeMs": 123
206
+ }
207
+ ```
208
+
209
+ ### reset_app_data
210
+ Clear app storage (reset to fresh install state).
89
211
 
90
212
  **Input:**
213
+ ```jsonc
214
+ {
215
+ "platform": "android" | "ios",
216
+ "appId": "com.example.app", // Android package or iOS bundle ID (Required)
217
+ "deviceId": "emulator-5554" // Optional
218
+ }
219
+ ```
91
220
 
221
+ **Response:**
92
222
  ```json
223
+ {
224
+ "device": { /* device info */ },
225
+ "dataCleared": true
226
+ }
227
+ ```
228
+
229
+ ### get_ui_tree
230
+ Get the current UI hierarchy from the device. Returns a structured JSON representation of the screen content.
231
+
232
+ **Input:**
233
+ ```jsonc
93
234
  {
94
235
  "platform": "android" | "ios",
95
- "lines": 200 // optional, Android only
236
+ "deviceId": "emulator-5554" // Optional
96
237
  }
97
238
  ```
98
239
 
99
- **Example:**
240
+ **Response:**
241
+ ```json
242
+ {
243
+ "device": { /* device info */ },
244
+ "screen": "",
245
+ "resolution": { "width": 1080, "height": 1920 },
246
+ "elements": [
247
+ {
248
+ "text": "Login",
249
+ "contentDescription": null,
250
+ "type": "android.widget.Button",
251
+ "resourceId": "com.example:id/login_button",
252
+ "clickable": true,
253
+ "enabled": true,
254
+ "visible": true,
255
+ "bounds": [120,400,280,450],
256
+ "center": [200, 425],
257
+ "depth": 1,
258
+ "parentId": 0,
259
+ "children": []
260
+ }
261
+ ]
262
+ }
263
+ ```
264
+
265
+ ### get_current_screen
266
+ Get the currently visible activity on an Android device.
267
+
268
+ **Input:**
269
+ ```jsonc
270
+ {
271
+ "deviceId": "emulator-5554" // Optional: target specific device
272
+ }
273
+ ```
100
274
 
275
+ **Response:**
101
276
  ```json
102
277
  {
103
- "platform": "android",
104
- "lines": 200
278
+ "device": { /* device info */ },
279
+ "package": "com.example.app",
280
+ "activity": "com.example.app.LoginActivity",
281
+ "shortActivity": "LoginActivity"
105
282
  }
106
283
  ```
107
284
 
@@ -112,15 +289,37 @@ Fetch recent logs from the app.
112
289
  1. Ensure Android device or iOS simulator is running.
113
290
  2. Use `start_app` to launch the app.
114
291
  3. Use `get_logs` to read the latest logs.
115
- 4. Repeat for debugging loops.
292
+ 4. Use `capture_screenshot` to visually inspect the app if needed.
293
+ 5. Use `reset_app_data` to clear state if debugging fresh install scenarios.
294
+ 6. Use `restart_app` to quickly reboot the app during development cycles.
116
295
 
117
296
  ---
118
297
 
119
298
  ## Notes
120
299
 
121
- - Ensure `adb` and `xcrun` are in your PATH.
122
- - For iOS, the simulator must be booted before using `start_app` or `get_logs`.
123
- - You may want to clear Android logs before launching for cleaner output: `adb logcat -c`
300
+ - Ensure `adb` and `xcrun` are in your PATH or set `ADB_PATH` / `XCRUN_PATH` accordingly.
301
+ - For iOS, the simulator must be booted before using tools.
302
+ - The `capture_screenshot` tool returns a multi-block response: a JSON text block with metadata, followed by an image block containing the base64-encoded PNG data.
303
+
304
+ ---
305
+
306
+ ## Testing
307
+
308
+ The repository includes a smoke test script to verify end-to-end functionality on real devices or simulators.
309
+
310
+ ```bash
311
+ # Run smoke test for Android
312
+ npx tsx smoke-test.ts android com.example.package
313
+
314
+ # Run smoke test for iOS
315
+ npx tsx smoke-test.ts ios com.example.bundleid
316
+ ```
317
+
318
+ The smoke test performs the following sequence:
319
+ 1. Starts the app
320
+ 2. Captures a screenshot
321
+ 3. Fetches logs
322
+ 4. Terminates the app
124
323
 
125
324
  ---
126
325
 
@@ -0,0 +1,30 @@
1
+ import { execAdb, getAndroidDeviceMetadata, getDeviceInfo } from "./utils.js";
2
+ export class AndroidInteract {
3
+ async startApp(appId, deviceId) {
4
+ const metadata = await getAndroidDeviceMetadata(appId, deviceId);
5
+ const deviceInfo = getDeviceInfo(deviceId || 'default', metadata);
6
+ await execAdb(['shell', 'monkey', '-p', appId, '-c', 'android.intent.category.LAUNCHER', '1'], deviceId);
7
+ return { device: deviceInfo, appStarted: true, launchTimeMs: 1000 };
8
+ }
9
+ async terminateApp(appId, deviceId) {
10
+ const metadata = await getAndroidDeviceMetadata(appId, deviceId);
11
+ const deviceInfo = getDeviceInfo(deviceId || 'default', metadata);
12
+ await execAdb(['shell', 'am', 'force-stop', appId], deviceId);
13
+ return { device: deviceInfo, appTerminated: true };
14
+ }
15
+ async restartApp(appId, deviceId) {
16
+ await this.terminateApp(appId, deviceId);
17
+ const startResult = await this.startApp(appId, deviceId);
18
+ return {
19
+ device: startResult.device,
20
+ appRestarted: startResult.appStarted,
21
+ launchTimeMs: startResult.launchTimeMs
22
+ };
23
+ }
24
+ async resetAppData(appId, deviceId) {
25
+ const metadata = await getAndroidDeviceMetadata(appId, deviceId);
26
+ const deviceInfo = getDeviceInfo(deviceId || 'default', metadata);
27
+ const output = await execAdb(['shell', 'pm', 'clear', appId], deviceId);
28
+ return { device: deviceInfo, dataCleared: output === 'Success' };
29
+ }
30
+ }