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.
- package/.github/copilot-instructions.md +33 -0
- package/README.md +220 -21
- package/dist/android/interact.js +30 -0
- package/dist/android/observe.js +313 -0
- package/dist/android/utils.js +82 -0
- package/dist/android.js +303 -31
- package/dist/ios/interact.js +65 -0
- package/dist/ios/observe.js +219 -0
- package/dist/ios/utils.js +114 -0
- package/dist/ios.js +337 -14
- package/dist/server.js +320 -20
- package/docs/CHANGELOG.md +28 -0
- package/package.json +3 -2
- package/smoke-test.js +102 -0
- package/smoke-test.ts +122 -0
- package/src/android/interact.ts +41 -0
- package/src/android/observe.ts +360 -0
- package/src/android/utils.ts +94 -0
- package/src/ios/interact.ts +75 -0
- package/src/ios/observe.ts +269 -0
- package/src/ios/utils.ts +133 -0
- package/src/server.ts +367 -24
- package/src/types.ts +92 -0
- package/test-ui-tree.js +68 -0
- package/test-ui-tree.ts +76 -0
- package/tsconfig.json +3 -1
- package/src/android.ts +0 -48
- package/src/ios.ts +0 -25
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
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": "
|
|
54
|
-
"args": [
|
|
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
|
|
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
|
-
"
|
|
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
|
-
**
|
|
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
|
-
"
|
|
83
|
-
"
|
|
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
|
-
###
|
|
88
|
-
|
|
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
|
-
"
|
|
236
|
+
"deviceId": "emulator-5554" // Optional
|
|
96
237
|
}
|
|
97
238
|
```
|
|
98
239
|
|
|
99
|
-
**
|
|
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
|
-
"
|
|
104
|
-
"
|
|
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.
|
|
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
|
|
123
|
-
-
|
|
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
|
+
}
|