mcp-maestro-mobile-ai 1.1.1 → 1.3.1

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 CHANGED
@@ -15,6 +15,38 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
15
15
 
16
16
  ---
17
17
 
18
+ ## [1.3.1] - 2025-01-06
19
+
20
+ ### Fixed
21
+ - **MCP Schema Fix**: Fixed `generate_report` tool array parameter missing `items` definition
22
+ - This was causing "tool parameters array type must have items" validation error
23
+ - Now properly defines the structure of test result objects
24
+
25
+ ---
26
+
27
+ ## [1.2.0] - 2025-01-06
28
+
29
+ ### Added
30
+ - **YAML Generation Instructions System**: Ensures consistent YAML generation across different environments
31
+ - `get_yaml_instructions` - AI MUST call this before generating YAML (provides exact rules)
32
+ - `validate_yaml_structure` - Validates YAML for common issues (like missing tapOn before inputText)
33
+ - `get_test_pattern` - Get standard patterns for login, search, navigation, form tests
34
+ - **Critical Fix**: Input text pattern now enforced - prevents password going to username field issue
35
+ - Standard test patterns for common scenarios (login, search, navigation, form)
36
+
37
+ ### Fixed
38
+ - YAML generation inconsistency between different environments
39
+ - Text input going to wrong fields due to missing tapOn commands
40
+
41
+ ---
42
+
43
+ ## [1.1.1] - 2025-01-06
44
+
45
+ ### Fixed
46
+ - Version bump for npm publish
47
+
48
+ ---
49
+
18
50
  ## [1.1.0] - 2025-01-06
19
51
 
20
52
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-maestro-mobile-ai",
3
- "version": "1.1.1",
3
+ "version": "1.3.1",
4
4
  "private": false,
5
5
  "description": "MCP Server for AI-Assisted Mobile Automation using Maestro - Run mobile tests with natural language prompts",
6
6
  "main": "src/mcp-server/index.js",
@@ -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,6 +45,10 @@ 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";
50
54
  import { validatePrerequisites } from "./utils/prerequisites.js";
@@ -58,7 +62,7 @@ config({ path: join(__dirname, "../../.env") });
58
62
  const server = new Server(
59
63
  {
60
64
  name: "mcp-maestro-mobile-ai",
61
- version: "1.1.0",
65
+ version: "1.2.0",
62
66
  },
63
67
  {
64
68
  capabilities: {
@@ -180,7 +184,7 @@ const TOOLS = [
180
184
  {
181
185
  name: "validate_maestro_yaml",
182
186
  description:
183
- "Validate a Maestro YAML flow for syntax errors before running. Returns validation result with any errors found.",
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!",
184
188
  inputSchema: {
185
189
  type: "object",
186
190
  properties: {
@@ -196,14 +200,31 @@ const TOOLS = [
196
200
  // === Test Execution Tools ===
197
201
  {
198
202
  name: "run_test",
199
- description:
200
- "Run a single Maestro test. Provide the Maestro YAML content directly. The test will be executed on the selected device (or first available if none selected). Includes pre-flight checks and auto-retry.",
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"`,
201
222
  inputSchema: {
202
223
  type: "object",
203
224
  properties: {
204
225
  yaml: {
205
226
  type: "string",
206
- description: "The Maestro YAML flow content to run",
227
+ description: "The Maestro YAML flow content. MUST use tapOn before inputText for each field!",
207
228
  },
208
229
  name: {
209
230
  type: "string",
@@ -221,7 +242,7 @@ const TOOLS = [
221
242
  {
222
243
  name: "run_test_suite",
223
244
  description:
224
- "Run multiple Maestro tests in sequence. Provide an array of test objects with yaml and name properties. Tests run on selected device.",
245
+ "Run multiple Maestro tests in sequence. Each YAML must follow the rules: appId at top, clearState, launchApp, and ALWAYS tapOn before inputText!",
225
246
  inputSchema: {
226
247
  type: "object",
227
248
  properties: {
@@ -232,7 +253,7 @@ const TOOLS = [
232
253
  properties: {
233
254
  yaml: {
234
255
  type: "string",
235
- description: "The Maestro YAML flow content",
256
+ description: "The Maestro YAML. MUST use tapOn before inputText!",
236
257
  },
237
258
  name: {
238
259
  type: "string",
@@ -253,7 +274,90 @@ const TOOLS = [
253
274
  },
254
275
  },
255
276
 
256
- // === Results & Utility Tools ===
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
+ items: {
329
+ type: "object",
330
+ properties: {
331
+ name: { type: "string", description: "Test name" },
332
+ success: { type: "boolean", description: "Whether the test passed" },
333
+ duration: { type: "number", description: "Test duration in milliseconds" },
334
+ error: { type: "string", description: "Error message if test failed" },
335
+ },
336
+ required: ["name", "success"],
337
+ },
338
+ description: "Array of test results with name, success, duration, error fields",
339
+ },
340
+ promptFile: {
341
+ type: "string",
342
+ description: "Name of the prompt file",
343
+ },
344
+ appId: {
345
+ type: "string",
346
+ description: "App ID",
347
+ },
348
+ },
349
+ required: ["results"],
350
+ },
351
+ },
352
+ {
353
+ name: "list_reports",
354
+ description:
355
+ "List all generated test reports. Returns paths to HTML and JSON report files.",
356
+ inputSchema: {
357
+ type: "object",
358
+ properties: {},
359
+ },
360
+ },
257
361
  {
258
362
  name: "get_test_results",
259
363
  description: "Get the results from the last test run or a specific run by ID.",
@@ -458,6 +562,62 @@ const TOOLS = [
458
562
  properties: {},
459
563
  },
460
564
  },
565
+
566
+ // === YAML Generation Tools (CRITICAL) ===
567
+ {
568
+ name: "get_yaml_instructions",
569
+ description:
570
+ "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.",
571
+ inputSchema: {
572
+ type: "object",
573
+ properties: {
574
+ appId: {
575
+ type: "string",
576
+ description: "App package ID to get app-specific context",
577
+ },
578
+ },
579
+ },
580
+ },
581
+ {
582
+ name: "validate_yaml_structure",
583
+ description:
584
+ "Validate YAML structure before running a test. Checks for common issues like missing 'tapOn' before 'inputText' which causes text to go to wrong fields.",
585
+ inputSchema: {
586
+ type: "object",
587
+ properties: {
588
+ yamlContent: {
589
+ type: "string",
590
+ description: "The Maestro YAML content to validate",
591
+ },
592
+ },
593
+ required: ["yamlContent"],
594
+ },
595
+ },
596
+ {
597
+ name: "get_test_pattern",
598
+ description:
599
+ "Get a standard test pattern template. Available: login, form, search, navigation, list, settings, logout. Use these as starting points.",
600
+ inputSchema: {
601
+ type: "object",
602
+ properties: {
603
+ patternName: {
604
+ type: "string",
605
+ description: "Pattern name: login, form, search, navigation, list, settings, or logout",
606
+ enum: ["login", "form", "search", "navigation", "list", "settings", "logout"],
607
+ },
608
+ },
609
+ required: ["patternName"],
610
+ },
611
+ },
612
+ {
613
+ name: "get_screen_analysis_help",
614
+ description:
615
+ "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.",
616
+ inputSchema: {
617
+ type: "object",
618
+ properties: {},
619
+ },
620
+ },
461
621
  ];
462
622
 
463
623
  // ============================================
@@ -515,7 +675,23 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
515
675
  case "run_test_suite":
516
676
  return await runTestSuite(args.tests, { retries: args.retries });
517
677
 
518
- // Results & utility tools
678
+ // Results & reporting tools
679
+ case "run_tests_with_report":
680
+ return await runTestSuiteWithReport(args.tests, {
681
+ promptFile: args.promptFile,
682
+ appId: args.appId,
683
+ retries: args.retries,
684
+ });
685
+
686
+ case "generate_report":
687
+ return await generateTestReport(args.results, {
688
+ promptFile: args.promptFile,
689
+ appId: args.appId,
690
+ });
691
+
692
+ case "list_reports":
693
+ return await listTestReports();
694
+
519
695
  case "get_test_results":
520
696
  return await getTestResults(args.runId);
521
697
 
@@ -556,6 +732,19 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
556
732
  case "list_app_contexts":
557
733
  return await listContexts();
558
734
 
735
+ // YAML generation tools
736
+ case "get_yaml_instructions":
737
+ return await getYamlInstructions(args.appId);
738
+
739
+ case "validate_yaml_structure":
740
+ return await validateYamlBeforeRun(args.yamlContent);
741
+
742
+ case "get_test_pattern":
743
+ return await getTestPattern(args.patternName);
744
+
745
+ case "get_screen_analysis_help":
746
+ return await getScreenAnalysis();
747
+
559
748
  default:
560
749
  throw new Error(`Unknown tool: ${name}`);
561
750
  }
@@ -612,7 +801,7 @@ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
612
801
  // ============================================
613
802
 
614
803
  async function main() {
615
- logger.info("Starting MCP Maestro Mobile AI v1.1.0...");
804
+ logger.info("Starting MCP Maestro Mobile AI v1.2.0...");
616
805
  logger.info("");
617
806
 
618
807
  // Validate prerequisites before starting
@@ -14,6 +14,13 @@ import {
14
14
  clearAppContext,
15
15
  listAppContexts,
16
16
  } from "../utils/appContext.js";
17
+ import {
18
+ YAML_GENERATION_INSTRUCTIONS,
19
+ getYamlGenerationContext,
20
+ TEST_PATTERNS,
21
+ validateYamlStructure,
22
+ getScreenAnalysisInstructions,
23
+ } from "../utils/yamlTemplate.js";
17
24
 
18
25
  /**
19
26
  * Format result as MCP response
@@ -180,6 +187,118 @@ export async function listContexts() {
180
187
  return formatResponse(result);
181
188
  }
182
189
 
190
+ /**
191
+ * Get YAML generation instructions
192
+ * AI MUST call this before generating any Maestro YAML
193
+ */
194
+ export async function getYamlInstructions(appId) {
195
+ if (!appId) {
196
+ // Return generic instructions without app context
197
+ return formatResponse({
198
+ success: true,
199
+ instructions: YAML_GENERATION_INSTRUCTIONS,
200
+ patterns: TEST_PATTERNS,
201
+ message: "Use these instructions when generating Maestro YAML. Always follow the tapOn → inputText pattern for text input.",
202
+ });
203
+ }
204
+
205
+ // Get app-specific context
206
+ const appContext = await loadAppContext(appId);
207
+ const instructions = getYamlGenerationContext(appId, appContext);
208
+
209
+ return formatResponse({
210
+ success: true,
211
+ appId,
212
+ instructions,
213
+ patterns: TEST_PATTERNS,
214
+ hasAppContext: Object.keys(appContext.elements || {}).length > 0,
215
+ message: "IMPORTANT: Follow these instructions EXACTLY when generating YAML. Always use tapOn before inputText.",
216
+ });
217
+ }
218
+
219
+ /**
220
+ * Validate YAML before running
221
+ * Checks for common issues like missing tapOn before inputText
222
+ */
223
+ export async function validateYamlBeforeRun(yamlContent) {
224
+ if (!yamlContent) {
225
+ return formatResponse({
226
+ success: false,
227
+ error: "yamlContent is required",
228
+ });
229
+ }
230
+
231
+ const validation = validateYamlStructure(yamlContent);
232
+
233
+ if (!validation.valid) {
234
+ return formatResponse({
235
+ success: false,
236
+ valid: false,
237
+ issues: validation.issues,
238
+ message: "YAML has structural issues that may cause test failures. Please fix before running.",
239
+ fixedYaml: null, // Could auto-fix in future
240
+ });
241
+ }
242
+
243
+ return formatResponse({
244
+ success: true,
245
+ valid: true,
246
+ message: "YAML structure is valid.",
247
+ });
248
+ }
249
+
250
+ /**
251
+ * Get a test pattern template
252
+ */
253
+ export async function getTestPattern(patternName) {
254
+ const patterns = {
255
+ login: TEST_PATTERNS.login,
256
+ search: TEST_PATTERNS.search,
257
+ navigation: TEST_PATTERNS.navigation,
258
+ form: TEST_PATTERNS.form,
259
+ list: TEST_PATTERNS.list,
260
+ settings: TEST_PATTERNS.settings,
261
+ logout: TEST_PATTERNS.logout,
262
+ };
263
+
264
+ const pattern = patterns[patternName?.toLowerCase()];
265
+
266
+ if (!pattern) {
267
+ return formatResponse({
268
+ success: false,
269
+ error: `Unknown pattern: ${patternName}`,
270
+ availablePatterns: Object.keys(patterns),
271
+ hint: "Use: login, form, search, navigation, list, settings, or logout",
272
+ });
273
+ }
274
+
275
+ return formatResponse({
276
+ success: true,
277
+ pattern: patternName,
278
+ template: pattern,
279
+ message: "Replace placeholders in {} with actual values. REMEMBER: Always use tapOn before inputText!",
280
+ });
281
+ }
282
+
283
+ /**
284
+ * Get screen analysis instructions
285
+ * Helps AI understand how to gather UI element information
286
+ */
287
+ export async function getScreenAnalysis() {
288
+ const instructions = getScreenAnalysisInstructions();
289
+
290
+ return formatResponse({
291
+ success: true,
292
+ instructions,
293
+ message: "Use these instructions to gather UI element information before generating YAML.",
294
+ requiredInfo: [
295
+ "Field labels/placeholders for text inputs",
296
+ "Button text for actions",
297
+ "Success/error indicators to verify results",
298
+ ],
299
+ });
300
+ }
301
+
183
302
  export default {
184
303
  registerAppElements,
185
304
  registerAppScreen,
@@ -190,5 +309,9 @@ export default {
190
309
  getAppContext,
191
310
  clearContext,
192
311
  listContexts,
312
+ getYamlInstructions,
313
+ validateYamlBeforeRun,
314
+ getTestPattern,
315
+ getScreenAnalysis,
193
316
  };
194
317