mcp-maestro-mobile-ai 1.1.0 → 1.3.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/CHANGELOG.md +29 -0
- package/docs/MCP_SETUP.md +246 -41
- package/package.json +4 -1
- package/scripts/check-prerequisites.js +277 -0
- package/src/mcp-server/index.js +202 -11
- package/src/mcp-server/tools/contextTools.js +123 -0
- package/src/mcp-server/tools/runTools.js +227 -4
- package/src/mcp-server/utils/prerequisites.js +390 -0
- package/src/mcp-server/utils/reportGenerator.js +455 -0
- package/src/mcp-server/utils/yamlTemplate.js +559 -0
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Postinstall Prerequisites Check
|
|
5
|
+
*
|
|
6
|
+
* This script runs after npm install to warn users about missing prerequisites.
|
|
7
|
+
* It shows warnings but does NOT block installation.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { execSync } from "child_process";
|
|
11
|
+
|
|
12
|
+
// ANSI color codes for terminal output
|
|
13
|
+
const colors = {
|
|
14
|
+
reset: "\x1b[0m",
|
|
15
|
+
bright: "\x1b[1m",
|
|
16
|
+
red: "\x1b[31m",
|
|
17
|
+
green: "\x1b[32m",
|
|
18
|
+
yellow: "\x1b[33m",
|
|
19
|
+
blue: "\x1b[34m",
|
|
20
|
+
cyan: "\x1b[36m",
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const icons = {
|
|
24
|
+
check: "✅",
|
|
25
|
+
cross: "❌",
|
|
26
|
+
warning: "⚠️",
|
|
27
|
+
info: "ℹ️",
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Execute a command and return the output
|
|
32
|
+
*/
|
|
33
|
+
function execCommand(command) {
|
|
34
|
+
try {
|
|
35
|
+
return execSync(command, {
|
|
36
|
+
encoding: "utf8",
|
|
37
|
+
timeout: 10000,
|
|
38
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
39
|
+
}).trim();
|
|
40
|
+
} catch (error) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Parse version string to extract major version number
|
|
47
|
+
*/
|
|
48
|
+
function parseVersion(versionString) {
|
|
49
|
+
if (!versionString) return null;
|
|
50
|
+
const match = versionString.match(/(\d+)\.(\d+)/);
|
|
51
|
+
if (match) {
|
|
52
|
+
return {
|
|
53
|
+
major: parseInt(match[1], 10),
|
|
54
|
+
minor: parseInt(match[2], 10),
|
|
55
|
+
full: versionString,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Check Node.js version
|
|
63
|
+
*/
|
|
64
|
+
function checkNodeJs() {
|
|
65
|
+
const version = process.version;
|
|
66
|
+
const parsed = parseVersion(version);
|
|
67
|
+
|
|
68
|
+
if (!parsed) {
|
|
69
|
+
return {
|
|
70
|
+
installed: false,
|
|
71
|
+
message: "Could not determine Node.js version"
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (parsed.major >= 18) {
|
|
76
|
+
return {
|
|
77
|
+
installed: true,
|
|
78
|
+
version: version,
|
|
79
|
+
message: `Node.js ${version}`
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
installed: true,
|
|
85
|
+
version: version,
|
|
86
|
+
outdated: true,
|
|
87
|
+
message: `Node.js ${version} (requires 18+)`
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Check Java version
|
|
93
|
+
*/
|
|
94
|
+
function checkJava() {
|
|
95
|
+
// Try java --version first (Java 9+)
|
|
96
|
+
let output = execCommand("java --version");
|
|
97
|
+
|
|
98
|
+
// Fall back to java -version (older format)
|
|
99
|
+
if (!output) {
|
|
100
|
+
output = execCommand("java -version 2>&1");
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (!output) {
|
|
104
|
+
return {
|
|
105
|
+
installed: false,
|
|
106
|
+
message: "Java not found",
|
|
107
|
+
hint: "Install Java 17+ from https://adoptium.net/"
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Parse Java version
|
|
112
|
+
const versionMatch = output.match(/(?:java|openjdk)\s+(?:version\s+)?["']?(\d+)(?:\.(\d+))?/i);
|
|
113
|
+
if (versionMatch) {
|
|
114
|
+
const major = parseInt(versionMatch[1], 10);
|
|
115
|
+
|
|
116
|
+
if (major >= 17) {
|
|
117
|
+
return {
|
|
118
|
+
installed: true,
|
|
119
|
+
version: `${major}`,
|
|
120
|
+
message: `Java ${major}`
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
installed: true,
|
|
126
|
+
version: `${major}`,
|
|
127
|
+
outdated: true,
|
|
128
|
+
message: `Java ${major} (requires 17+)`,
|
|
129
|
+
hint: "Upgrade to Java 17+ from https://adoptium.net/"
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
installed: true,
|
|
135
|
+
message: "Java (version unknown)"
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Check Maestro CLI
|
|
141
|
+
*/
|
|
142
|
+
function checkMaestro() {
|
|
143
|
+
const output = execCommand("maestro --version");
|
|
144
|
+
|
|
145
|
+
if (!output) {
|
|
146
|
+
return {
|
|
147
|
+
installed: false,
|
|
148
|
+
message: "Maestro CLI not found",
|
|
149
|
+
hint: "Install: curl -Ls https://get.maestro.mobile.dev | bash"
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return {
|
|
154
|
+
installed: true,
|
|
155
|
+
version: output,
|
|
156
|
+
message: `Maestro ${output}`
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Check Android SDK / ADB
|
|
162
|
+
*/
|
|
163
|
+
function checkAndroidSdk() {
|
|
164
|
+
const androidHome = process.env.ANDROID_HOME;
|
|
165
|
+
|
|
166
|
+
if (!androidHome) {
|
|
167
|
+
return {
|
|
168
|
+
installed: false,
|
|
169
|
+
message: "ANDROID_HOME not set",
|
|
170
|
+
hint: "Set ANDROID_HOME environment variable to your Android SDK path"
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Check if ADB exists
|
|
175
|
+
const adbOutput = execCommand("adb --version");
|
|
176
|
+
|
|
177
|
+
if (!adbOutput) {
|
|
178
|
+
return {
|
|
179
|
+
installed: true,
|
|
180
|
+
message: "ANDROID_HOME set but ADB not in PATH",
|
|
181
|
+
hint: "Add Android SDK platform-tools to your PATH"
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return {
|
|
186
|
+
installed: true,
|
|
187
|
+
message: `Android SDK (${androidHome.length > 40 ? "..." + androidHome.slice(-37) : androidHome})`
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Main check function
|
|
193
|
+
*/
|
|
194
|
+
function runChecks() {
|
|
195
|
+
console.log("");
|
|
196
|
+
console.log(`${colors.cyan}${colors.bright}╔════════════════════════════════════════════════════════╗${colors.reset}`);
|
|
197
|
+
console.log(`${colors.cyan}${colors.bright}║ MCP Maestro Mobile AI - Prerequisites ║${colors.reset}`);
|
|
198
|
+
console.log(`${colors.cyan}${colors.bright}╚════════════════════════════════════════════════════════╝${colors.reset}`);
|
|
199
|
+
console.log("");
|
|
200
|
+
|
|
201
|
+
const checks = [
|
|
202
|
+
{ name: "Node.js 18+", check: checkNodeJs, required: true },
|
|
203
|
+
{ name: "Java 17+", check: checkJava, required: true },
|
|
204
|
+
{ name: "Maestro CLI", check: checkMaestro, required: true },
|
|
205
|
+
{ name: "Android SDK", check: checkAndroidSdk, required: false },
|
|
206
|
+
];
|
|
207
|
+
|
|
208
|
+
const results = [];
|
|
209
|
+
let hasErrors = false;
|
|
210
|
+
let hasWarnings = false;
|
|
211
|
+
|
|
212
|
+
for (const item of checks) {
|
|
213
|
+
const result = item.check();
|
|
214
|
+
results.push({ ...item, result });
|
|
215
|
+
|
|
216
|
+
let icon, color;
|
|
217
|
+
|
|
218
|
+
if (result.installed && !result.outdated) {
|
|
219
|
+
icon = icons.check;
|
|
220
|
+
color = colors.green;
|
|
221
|
+
} else if (result.outdated) {
|
|
222
|
+
icon = icons.warning;
|
|
223
|
+
color = colors.yellow;
|
|
224
|
+
hasWarnings = true;
|
|
225
|
+
if (item.required) hasErrors = true;
|
|
226
|
+
} else {
|
|
227
|
+
icon = item.required ? icons.cross : icons.warning;
|
|
228
|
+
color = item.required ? colors.red : colors.yellow;
|
|
229
|
+
if (item.required) {
|
|
230
|
+
hasErrors = true;
|
|
231
|
+
} else {
|
|
232
|
+
hasWarnings = true;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
console.log(` ${icon} ${color}${result.message}${colors.reset}`);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
console.log("");
|
|
240
|
+
|
|
241
|
+
// Show hints for missing/outdated items
|
|
242
|
+
const hints = results
|
|
243
|
+
.filter(r => r.result.hint)
|
|
244
|
+
.map(r => r.result.hint);
|
|
245
|
+
|
|
246
|
+
if (hints.length > 0) {
|
|
247
|
+
console.log(`${colors.yellow}${icons.info} Installation hints:${colors.reset}`);
|
|
248
|
+
hints.forEach(hint => {
|
|
249
|
+
console.log(` ${colors.yellow}→ ${hint}${colors.reset}`);
|
|
250
|
+
});
|
|
251
|
+
console.log("");
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Summary
|
|
255
|
+
if (hasErrors) {
|
|
256
|
+
console.log(`${colors.red}${colors.bright}⚠️ Some required prerequisites are missing.${colors.reset}`);
|
|
257
|
+
console.log(`${colors.red} The server will not start without them.${colors.reset}`);
|
|
258
|
+
console.log("");
|
|
259
|
+
} else if (hasWarnings) {
|
|
260
|
+
console.log(`${colors.yellow}${colors.bright}${icons.warning} Some optional prerequisites are missing.${colors.reset}`);
|
|
261
|
+
console.log(`${colors.yellow} The server may have limited functionality.${colors.reset}`);
|
|
262
|
+
console.log("");
|
|
263
|
+
} else {
|
|
264
|
+
console.log(`${colors.green}${colors.bright}${icons.check} All prerequisites satisfied!${colors.reset}`);
|
|
265
|
+
console.log("");
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
console.log(`${colors.cyan}Documentation: https://github.com/krunal-mahera/mcp-maestro-mobile-ai${colors.reset}`);
|
|
269
|
+
console.log("");
|
|
270
|
+
|
|
271
|
+
// Note: We do NOT exit with error code - this is just a warning
|
|
272
|
+
// The actual validation happens at runtime
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Run checks
|
|
276
|
+
runChecks();
|
|
277
|
+
|
package/src/mcp-server/index.js
CHANGED
|
@@ -23,7 +23,7 @@ import { dirname, join } from "path";
|
|
|
23
23
|
// Import tools
|
|
24
24
|
import { readPromptFile, listPromptFiles } from "./tools/promptTools.js";
|
|
25
25
|
import { validateMaestroYaml } from "./tools/validateTools.js";
|
|
26
|
-
import { runTest, runTestSuite } from "./tools/runTools.js";
|
|
26
|
+
import { runTest, runTestSuite, generateTestReport, listTestReports, runTestSuiteWithReport } from "./tools/runTools.js";
|
|
27
27
|
import {
|
|
28
28
|
getAppConfig,
|
|
29
29
|
getTestResults,
|
|
@@ -45,8 +45,13 @@ import {
|
|
|
45
45
|
getAppContext,
|
|
46
46
|
clearContext,
|
|
47
47
|
listContexts,
|
|
48
|
+
getYamlInstructions,
|
|
49
|
+
validateYamlBeforeRun,
|
|
50
|
+
getTestPattern,
|
|
51
|
+
getScreenAnalysis,
|
|
48
52
|
} from "./tools/contextTools.js";
|
|
49
53
|
import { logger } from "./utils/logger.js";
|
|
54
|
+
import { validatePrerequisites } from "./utils/prerequisites.js";
|
|
50
55
|
|
|
51
56
|
// Load environment variables
|
|
52
57
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -57,7 +62,7 @@ config({ path: join(__dirname, "../../.env") });
|
|
|
57
62
|
const server = new Server(
|
|
58
63
|
{
|
|
59
64
|
name: "mcp-maestro-mobile-ai",
|
|
60
|
-
version: "1.
|
|
65
|
+
version: "1.2.0",
|
|
61
66
|
},
|
|
62
67
|
{
|
|
63
68
|
capabilities: {
|
|
@@ -179,7 +184,7 @@ const TOOLS = [
|
|
|
179
184
|
{
|
|
180
185
|
name: "validate_maestro_yaml",
|
|
181
186
|
description:
|
|
182
|
-
"Validate
|
|
187
|
+
"Validate Maestro YAML for syntax AND structure errors. Checks for: missing appId, missing clearState/launchApp, inputText without tapOn (which causes text to go to wrong fields). Always validate before running!",
|
|
183
188
|
inputSchema: {
|
|
184
189
|
type: "object",
|
|
185
190
|
properties: {
|
|
@@ -195,14 +200,31 @@ const TOOLS = [
|
|
|
195
200
|
// === Test Execution Tools ===
|
|
196
201
|
{
|
|
197
202
|
name: "run_test",
|
|
198
|
-
description:
|
|
199
|
-
|
|
203
|
+
description: `Run a single Maestro test. IMPORTANT: The YAML MUST follow these rules or it will be REJECTED:
|
|
204
|
+
|
|
205
|
+
1. STRUCTURE: Must start with appId, then clearState, then launchApp
|
|
206
|
+
2. TEXT INPUT: ALWAYS use tapOn BEFORE inputText (or text goes to wrong field!)
|
|
207
|
+
CORRECT: - tapOn: "Username" then - inputText: "value"
|
|
208
|
+
WRONG: - inputText: "value" (missing tapOn!)
|
|
209
|
+
3. Use visible text labels for elements when testIDs are unknown
|
|
210
|
+
|
|
211
|
+
Example valid YAML:
|
|
212
|
+
appId: com.example.app
|
|
213
|
+
---
|
|
214
|
+
- clearState
|
|
215
|
+
- launchApp
|
|
216
|
+
- tapOn: "Username"
|
|
217
|
+
- inputText: "user@example.com"
|
|
218
|
+
- tapOn: "Password"
|
|
219
|
+
- inputText: "password123"
|
|
220
|
+
- tapOn: "Sign In"
|
|
221
|
+
- assertVisible: "Welcome"`,
|
|
200
222
|
inputSchema: {
|
|
201
223
|
type: "object",
|
|
202
224
|
properties: {
|
|
203
225
|
yaml: {
|
|
204
226
|
type: "string",
|
|
205
|
-
description: "The Maestro YAML flow content
|
|
227
|
+
description: "The Maestro YAML flow content. MUST use tapOn before inputText for each field!",
|
|
206
228
|
},
|
|
207
229
|
name: {
|
|
208
230
|
type: "string",
|
|
@@ -220,7 +242,7 @@ const TOOLS = [
|
|
|
220
242
|
{
|
|
221
243
|
name: "run_test_suite",
|
|
222
244
|
description:
|
|
223
|
-
"Run multiple Maestro tests in sequence.
|
|
245
|
+
"Run multiple Maestro tests in sequence. Each YAML must follow the rules: appId at top, clearState, launchApp, and ALWAYS tapOn before inputText!",
|
|
224
246
|
inputSchema: {
|
|
225
247
|
type: "object",
|
|
226
248
|
properties: {
|
|
@@ -231,7 +253,7 @@ const TOOLS = [
|
|
|
231
253
|
properties: {
|
|
232
254
|
yaml: {
|
|
233
255
|
type: "string",
|
|
234
|
-
description: "The Maestro YAML
|
|
256
|
+
description: "The Maestro YAML. MUST use tapOn before inputText!",
|
|
235
257
|
},
|
|
236
258
|
name: {
|
|
237
259
|
type: "string",
|
|
@@ -252,7 +274,80 @@ const TOOLS = [
|
|
|
252
274
|
},
|
|
253
275
|
},
|
|
254
276
|
|
|
255
|
-
// === Results &
|
|
277
|
+
// === Results & Reporting Tools ===
|
|
278
|
+
{
|
|
279
|
+
name: "run_tests_with_report",
|
|
280
|
+
description:
|
|
281
|
+
"Run multiple tests and automatically generate HTML + JSON report. Use this when running tests from a prompt file. Returns report path that can be opened in browser.",
|
|
282
|
+
inputSchema: {
|
|
283
|
+
type: "object",
|
|
284
|
+
properties: {
|
|
285
|
+
tests: {
|
|
286
|
+
type: "array",
|
|
287
|
+
items: {
|
|
288
|
+
type: "object",
|
|
289
|
+
properties: {
|
|
290
|
+
yaml: {
|
|
291
|
+
type: "string",
|
|
292
|
+
description: "The Maestro YAML. MUST use tapOn before inputText!",
|
|
293
|
+
},
|
|
294
|
+
name: {
|
|
295
|
+
type: "string",
|
|
296
|
+
description: "Name for this test",
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
required: ["yaml", "name"],
|
|
300
|
+
},
|
|
301
|
+
description: "Array of tests to run",
|
|
302
|
+
},
|
|
303
|
+
promptFile: {
|
|
304
|
+
type: "string",
|
|
305
|
+
description: "Name of the prompt file (for report metadata)",
|
|
306
|
+
},
|
|
307
|
+
appId: {
|
|
308
|
+
type: "string",
|
|
309
|
+
description: "App ID (for report metadata)",
|
|
310
|
+
},
|
|
311
|
+
retries: {
|
|
312
|
+
type: "number",
|
|
313
|
+
description: "Number of retries for failed tests",
|
|
314
|
+
},
|
|
315
|
+
},
|
|
316
|
+
required: ["tests"],
|
|
317
|
+
},
|
|
318
|
+
},
|
|
319
|
+
{
|
|
320
|
+
name: "generate_report",
|
|
321
|
+
description:
|
|
322
|
+
"Generate HTML and JSON report from test results. Call this after running tests to create a visual summary report.",
|
|
323
|
+
inputSchema: {
|
|
324
|
+
type: "object",
|
|
325
|
+
properties: {
|
|
326
|
+
results: {
|
|
327
|
+
type: "array",
|
|
328
|
+
description: "Array of test results with name, success, duration, error fields",
|
|
329
|
+
},
|
|
330
|
+
promptFile: {
|
|
331
|
+
type: "string",
|
|
332
|
+
description: "Name of the prompt file",
|
|
333
|
+
},
|
|
334
|
+
appId: {
|
|
335
|
+
type: "string",
|
|
336
|
+
description: "App ID",
|
|
337
|
+
},
|
|
338
|
+
},
|
|
339
|
+
required: ["results"],
|
|
340
|
+
},
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
name: "list_reports",
|
|
344
|
+
description:
|
|
345
|
+
"List all generated test reports. Returns paths to HTML and JSON report files.",
|
|
346
|
+
inputSchema: {
|
|
347
|
+
type: "object",
|
|
348
|
+
properties: {},
|
|
349
|
+
},
|
|
350
|
+
},
|
|
256
351
|
{
|
|
257
352
|
name: "get_test_results",
|
|
258
353
|
description: "Get the results from the last test run or a specific run by ID.",
|
|
@@ -457,6 +552,62 @@ const TOOLS = [
|
|
|
457
552
|
properties: {},
|
|
458
553
|
},
|
|
459
554
|
},
|
|
555
|
+
|
|
556
|
+
// === YAML Generation Tools (CRITICAL) ===
|
|
557
|
+
{
|
|
558
|
+
name: "get_yaml_instructions",
|
|
559
|
+
description:
|
|
560
|
+
"CRITICAL: Call this BEFORE generating any Maestro YAML. Returns the exact rules and patterns for generating valid YAML that works consistently. Includes app-specific context if available.",
|
|
561
|
+
inputSchema: {
|
|
562
|
+
type: "object",
|
|
563
|
+
properties: {
|
|
564
|
+
appId: {
|
|
565
|
+
type: "string",
|
|
566
|
+
description: "App package ID to get app-specific context",
|
|
567
|
+
},
|
|
568
|
+
},
|
|
569
|
+
},
|
|
570
|
+
},
|
|
571
|
+
{
|
|
572
|
+
name: "validate_yaml_structure",
|
|
573
|
+
description:
|
|
574
|
+
"Validate YAML structure before running a test. Checks for common issues like missing 'tapOn' before 'inputText' which causes text to go to wrong fields.",
|
|
575
|
+
inputSchema: {
|
|
576
|
+
type: "object",
|
|
577
|
+
properties: {
|
|
578
|
+
yamlContent: {
|
|
579
|
+
type: "string",
|
|
580
|
+
description: "The Maestro YAML content to validate",
|
|
581
|
+
},
|
|
582
|
+
},
|
|
583
|
+
required: ["yamlContent"],
|
|
584
|
+
},
|
|
585
|
+
},
|
|
586
|
+
{
|
|
587
|
+
name: "get_test_pattern",
|
|
588
|
+
description:
|
|
589
|
+
"Get a standard test pattern template. Available: login, form, search, navigation, list, settings, logout. Use these as starting points.",
|
|
590
|
+
inputSchema: {
|
|
591
|
+
type: "object",
|
|
592
|
+
properties: {
|
|
593
|
+
patternName: {
|
|
594
|
+
type: "string",
|
|
595
|
+
description: "Pattern name: login, form, search, navigation, list, settings, or logout",
|
|
596
|
+
enum: ["login", "form", "search", "navigation", "list", "settings", "logout"],
|
|
597
|
+
},
|
|
598
|
+
},
|
|
599
|
+
required: ["patternName"],
|
|
600
|
+
},
|
|
601
|
+
},
|
|
602
|
+
{
|
|
603
|
+
name: "get_screen_analysis_help",
|
|
604
|
+
description:
|
|
605
|
+
"Get instructions on how to gather UI element information from the user. Call this when you don't know the exact element names/labels on a screen. Returns questions to ask the user.",
|
|
606
|
+
inputSchema: {
|
|
607
|
+
type: "object",
|
|
608
|
+
properties: {},
|
|
609
|
+
},
|
|
610
|
+
},
|
|
460
611
|
];
|
|
461
612
|
|
|
462
613
|
// ============================================
|
|
@@ -514,7 +665,23 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
514
665
|
case "run_test_suite":
|
|
515
666
|
return await runTestSuite(args.tests, { retries: args.retries });
|
|
516
667
|
|
|
517
|
-
// Results &
|
|
668
|
+
// Results & reporting tools
|
|
669
|
+
case "run_tests_with_report":
|
|
670
|
+
return await runTestSuiteWithReport(args.tests, {
|
|
671
|
+
promptFile: args.promptFile,
|
|
672
|
+
appId: args.appId,
|
|
673
|
+
retries: args.retries,
|
|
674
|
+
});
|
|
675
|
+
|
|
676
|
+
case "generate_report":
|
|
677
|
+
return await generateTestReport(args.results, {
|
|
678
|
+
promptFile: args.promptFile,
|
|
679
|
+
appId: args.appId,
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
case "list_reports":
|
|
683
|
+
return await listTestReports();
|
|
684
|
+
|
|
518
685
|
case "get_test_results":
|
|
519
686
|
return await getTestResults(args.runId);
|
|
520
687
|
|
|
@@ -555,6 +722,19 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
555
722
|
case "list_app_contexts":
|
|
556
723
|
return await listContexts();
|
|
557
724
|
|
|
725
|
+
// YAML generation tools
|
|
726
|
+
case "get_yaml_instructions":
|
|
727
|
+
return await getYamlInstructions(args.appId);
|
|
728
|
+
|
|
729
|
+
case "validate_yaml_structure":
|
|
730
|
+
return await validateYamlBeforeRun(args.yamlContent);
|
|
731
|
+
|
|
732
|
+
case "get_test_pattern":
|
|
733
|
+
return await getTestPattern(args.patternName);
|
|
734
|
+
|
|
735
|
+
case "get_screen_analysis_help":
|
|
736
|
+
return await getScreenAnalysis();
|
|
737
|
+
|
|
558
738
|
default:
|
|
559
739
|
throw new Error(`Unknown tool: ${name}`);
|
|
560
740
|
}
|
|
@@ -611,7 +791,18 @@ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
|
611
791
|
// ============================================
|
|
612
792
|
|
|
613
793
|
async function main() {
|
|
614
|
-
logger.info("Starting MCP Maestro Mobile AI v1.
|
|
794
|
+
logger.info("Starting MCP Maestro Mobile AI v1.2.0...");
|
|
795
|
+
logger.info("");
|
|
796
|
+
|
|
797
|
+
// Validate prerequisites before starting
|
|
798
|
+
// This will exit with code 2 if critical prerequisites are missing
|
|
799
|
+
await validatePrerequisites({
|
|
800
|
+
exitOnError: true,
|
|
801
|
+
checkDevice: false, // Don't require device at startup
|
|
802
|
+
});
|
|
803
|
+
|
|
804
|
+
logger.info("");
|
|
805
|
+
logger.info("Prerequisites validated. Starting server...");
|
|
615
806
|
|
|
616
807
|
const transport = new StdioServerTransport();
|
|
617
808
|
await server.connect(transport);
|