@browserstack/mcp-server 1.2.3 → 1.2.5

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.
Files changed (164) hide show
  1. package/README.md +96 -6
  2. package/dist/lib/apiClient.d.ts +7 -5
  3. package/dist/lib/apiClient.js +76 -15
  4. package/dist/lib/device-cache.d.ts +3 -1
  5. package/dist/lib/device-cache.js +24 -17
  6. package/dist/lib/inmemory-store.d.ts +1 -0
  7. package/dist/lib/inmemory-store.js +1 -0
  8. package/dist/lib/instrumentation.js +6 -3
  9. package/dist/lib/utils.d.ts +78 -0
  10. package/dist/lib/utils.js +47 -0
  11. package/dist/lib/version-resolver.js +26 -14
  12. package/dist/server-factory.js +6 -0
  13. package/dist/tools/add-percy-snapshots.d.ts +5 -0
  14. package/dist/tools/add-percy-snapshots.js +17 -0
  15. package/dist/tools/appautomate-utils/appium-sdk/config-generator.d.ts +7 -0
  16. package/dist/tools/appautomate-utils/appium-sdk/config-generator.js +70 -0
  17. package/dist/tools/appautomate-utils/appium-sdk/constants.d.ts +23 -0
  18. package/dist/tools/appautomate-utils/appium-sdk/constants.js +64 -0
  19. package/dist/tools/appautomate-utils/appium-sdk/formatter.d.ts +8 -0
  20. package/dist/tools/appautomate-utils/appium-sdk/formatter.js +59 -0
  21. package/dist/tools/appautomate-utils/appium-sdk/handler.d.ts +3 -0
  22. package/dist/tools/appautomate-utils/appium-sdk/handler.js +66 -0
  23. package/dist/tools/appautomate-utils/appium-sdk/index.d.ts +7 -0
  24. package/dist/tools/appautomate-utils/appium-sdk/index.js +8 -0
  25. package/dist/tools/appautomate-utils/appium-sdk/instructions.d.ts +3 -0
  26. package/dist/tools/appautomate-utils/appium-sdk/instructions.js +47 -0
  27. package/dist/tools/appautomate-utils/appium-sdk/languages/csharp.d.ts +2 -0
  28. package/dist/tools/appautomate-utils/appium-sdk/languages/csharp.js +78 -0
  29. package/dist/tools/appautomate-utils/appium-sdk/languages/java.d.ts +10 -0
  30. package/dist/tools/appautomate-utils/appium-sdk/languages/java.js +121 -0
  31. package/dist/tools/appautomate-utils/appium-sdk/languages/nodejs.d.ts +3 -0
  32. package/dist/tools/appautomate-utils/appium-sdk/languages/nodejs.js +194 -0
  33. package/dist/tools/appautomate-utils/appium-sdk/languages/python.d.ts +3 -0
  34. package/dist/tools/appautomate-utils/appium-sdk/languages/python.js +76 -0
  35. package/dist/tools/appautomate-utils/appium-sdk/languages/ruby.d.ts +2 -0
  36. package/dist/tools/appautomate-utils/appium-sdk/languages/ruby.js +85 -0
  37. package/dist/tools/appautomate-utils/appium-sdk/types.d.ts +58 -0
  38. package/dist/tools/appautomate-utils/appium-sdk/types.js +63 -0
  39. package/dist/tools/appautomate-utils/appium-sdk/utils.d.ts +17 -0
  40. package/dist/tools/appautomate-utils/appium-sdk/utils.js +64 -0
  41. package/dist/tools/appautomate-utils/{appautomate.d.ts → native-execution/appautomate.d.ts} +1 -1
  42. package/dist/tools/appautomate-utils/{appautomate.js → native-execution/appautomate.js} +2 -2
  43. package/dist/tools/appautomate-utils/native-execution/constants.d.ts +11 -0
  44. package/dist/tools/appautomate-utils/native-execution/constants.js +58 -0
  45. package/dist/tools/appautomate-utils/native-execution/types.d.ts +19 -0
  46. package/dist/tools/appautomate-utils/{types.js → native-execution/types.js} +5 -1
  47. package/dist/tools/appautomate.js +40 -42
  48. package/dist/tools/bstack-sdk.d.ts +2 -15
  49. package/dist/tools/bstack-sdk.js +10 -119
  50. package/dist/tools/build-insights.d.ts +7 -0
  51. package/dist/tools/build-insights.js +67 -0
  52. package/dist/tools/list-test-files.d.ts +2 -0
  53. package/dist/tools/list-test-files.js +36 -0
  54. package/dist/tools/percy-sdk.d.ts +4 -0
  55. package/dist/tools/percy-sdk.js +98 -0
  56. package/dist/tools/percy-snapshot-utils/constants.d.ts +16 -0
  57. package/dist/tools/percy-snapshot-utils/constants.js +500 -0
  58. package/dist/tools/percy-snapshot-utils/detect-test-files.d.ts +10 -0
  59. package/dist/tools/percy-snapshot-utils/detect-test-files.js +175 -0
  60. package/dist/tools/percy-snapshot-utils/types.d.ts +15 -0
  61. package/dist/tools/percy-snapshot-utils/utils.d.ts +4 -0
  62. package/dist/tools/percy-snapshot-utils/utils.js +30 -0
  63. package/dist/tools/rca-agent-utils/constants.d.ts +13 -0
  64. package/dist/tools/rca-agent-utils/constants.js +24 -0
  65. package/dist/tools/rca-agent-utils/format-rca.d.ts +1 -0
  66. package/dist/tools/rca-agent-utils/format-rca.js +37 -0
  67. package/dist/tools/rca-agent-utils/get-build-id.d.ts +1 -0
  68. package/dist/tools/rca-agent-utils/get-build-id.js +18 -0
  69. package/dist/tools/rca-agent-utils/get-failed-test-id.d.ts +2 -0
  70. package/dist/tools/rca-agent-utils/get-failed-test-id.js +69 -0
  71. package/dist/tools/rca-agent-utils/rca-data.d.ts +9 -0
  72. package/dist/tools/rca-agent-utils/rca-data.js +196 -0
  73. package/dist/tools/rca-agent-utils/types.d.ts +48 -0
  74. package/dist/tools/rca-agent-utils/types.js +20 -0
  75. package/dist/tools/rca-agent.d.ts +14 -0
  76. package/dist/tools/rca-agent.js +119 -0
  77. package/dist/tools/review-agent-utils/build-counts.d.ts +7 -0
  78. package/dist/tools/review-agent-utils/build-counts.js +44 -0
  79. package/dist/tools/review-agent-utils/percy-approve-reject.d.ts +6 -0
  80. package/dist/tools/review-agent-utils/percy-approve-reject.js +39 -0
  81. package/dist/tools/review-agent-utils/percy-diffs.d.ts +9 -0
  82. package/dist/tools/review-agent-utils/percy-diffs.js +35 -0
  83. package/dist/tools/review-agent-utils/percy-snapshots.d.ts +11 -0
  84. package/dist/tools/review-agent-utils/percy-snapshots.js +58 -0
  85. package/dist/tools/review-agent.d.ts +5 -0
  86. package/dist/tools/review-agent.js +56 -0
  87. package/dist/tools/run-percy-scan.d.ts +8 -0
  88. package/dist/tools/run-percy-scan.js +37 -0
  89. package/dist/tools/sdk-utils/{commands.d.ts → bstack/commands.d.ts} +1 -1
  90. package/dist/tools/sdk-utils/bstack/commands.js +88 -0
  91. package/dist/tools/sdk-utils/bstack/configUtils.d.ts +7 -0
  92. package/dist/tools/sdk-utils/bstack/configUtils.js +113 -0
  93. package/dist/tools/sdk-utils/bstack/constants.d.ts +58 -0
  94. package/dist/tools/sdk-utils/{constants.js → bstack/constants.js} +117 -78
  95. package/dist/tools/sdk-utils/{constants.d.ts → bstack/frameworks.d.ts} +1 -1
  96. package/dist/tools/sdk-utils/bstack/frameworks.js +57 -0
  97. package/dist/tools/sdk-utils/bstack/index.d.ts +4 -0
  98. package/dist/tools/sdk-utils/bstack/index.js +5 -0
  99. package/dist/tools/sdk-utils/bstack/sdkHandler.d.ts +4 -0
  100. package/dist/tools/sdk-utils/bstack/sdkHandler.js +82 -0
  101. package/dist/tools/sdk-utils/common/constants.d.ts +11 -0
  102. package/dist/tools/sdk-utils/common/constants.js +87 -0
  103. package/dist/tools/sdk-utils/common/device-validator.d.ts +25 -0
  104. package/dist/tools/sdk-utils/common/device-validator.js +368 -0
  105. package/dist/tools/sdk-utils/common/formatUtils.d.ts +5 -0
  106. package/dist/tools/sdk-utils/common/formatUtils.js +27 -0
  107. package/dist/tools/sdk-utils/common/index.d.ts +3 -0
  108. package/dist/tools/sdk-utils/common/index.js +4 -0
  109. package/dist/tools/sdk-utils/common/instructionUtils.d.ts +8 -0
  110. package/dist/tools/sdk-utils/common/instructionUtils.js +20 -0
  111. package/dist/tools/sdk-utils/common/schema.d.ts +93 -0
  112. package/dist/tools/sdk-utils/common/schema.js +105 -0
  113. package/dist/tools/sdk-utils/common/types.d.ts +66 -0
  114. package/dist/tools/sdk-utils/{types.js → common/types.js} +15 -2
  115. package/dist/tools/sdk-utils/common/utils.d.ts +25 -0
  116. package/dist/tools/sdk-utils/common/utils.js +91 -0
  117. package/dist/tools/sdk-utils/handler.d.ts +5 -0
  118. package/dist/tools/sdk-utils/handler.js +147 -0
  119. package/dist/tools/sdk-utils/percy-automate/constants.d.ts +11 -0
  120. package/dist/tools/sdk-utils/percy-automate/constants.js +338 -0
  121. package/dist/tools/sdk-utils/percy-automate/frameworks.d.ts +8 -0
  122. package/dist/tools/sdk-utils/percy-automate/frameworks.js +50 -0
  123. package/dist/tools/sdk-utils/percy-automate/handler.d.ts +3 -0
  124. package/dist/tools/sdk-utils/percy-automate/handler.js +30 -0
  125. package/dist/tools/sdk-utils/percy-automate/index.d.ts +1 -0
  126. package/dist/tools/sdk-utils/percy-automate/index.js +2 -0
  127. package/dist/tools/sdk-utils/percy-automate/types.d.ts +13 -0
  128. package/dist/tools/sdk-utils/percy-automate/types.js +1 -0
  129. package/dist/tools/sdk-utils/percy-bstack/constants.d.ts +4 -0
  130. package/dist/tools/sdk-utils/{percy → percy-bstack}/constants.js +13 -39
  131. package/dist/tools/sdk-utils/percy-bstack/frameworks.d.ts +2 -0
  132. package/dist/tools/sdk-utils/percy-bstack/frameworks.js +27 -0
  133. package/dist/tools/sdk-utils/percy-bstack/handler.d.ts +4 -0
  134. package/dist/tools/sdk-utils/percy-bstack/handler.js +103 -0
  135. package/dist/tools/sdk-utils/percy-bstack/index.d.ts +4 -0
  136. package/dist/tools/sdk-utils/percy-bstack/index.js +4 -0
  137. package/dist/tools/sdk-utils/percy-bstack/instructions.d.ts +7 -0
  138. package/dist/tools/sdk-utils/{percy → percy-bstack}/instructions.js +5 -9
  139. package/dist/tools/sdk-utils/percy-bstack/types.d.ts +13 -0
  140. package/dist/tools/sdk-utils/percy-bstack/types.js +5 -0
  141. package/dist/tools/sdk-utils/percy-web/constants.d.ts +41 -0
  142. package/dist/tools/sdk-utils/percy-web/constants.js +883 -0
  143. package/dist/tools/sdk-utils/percy-web/fetchPercyToken.d.ts +4 -0
  144. package/dist/tools/sdk-utils/percy-web/fetchPercyToken.js +32 -0
  145. package/dist/tools/sdk-utils/percy-web/frameworks.d.ts +7 -0
  146. package/dist/tools/sdk-utils/percy-web/frameworks.js +103 -0
  147. package/dist/tools/sdk-utils/percy-web/handler.d.ts +4 -0
  148. package/dist/tools/sdk-utils/percy-web/handler.js +29 -0
  149. package/dist/tools/sdk-utils/percy-web/index.d.ts +4 -0
  150. package/dist/tools/sdk-utils/percy-web/index.js +4 -0
  151. package/dist/tools/sdk-utils/percy-web/types.d.ts +12 -0
  152. package/dist/tools/sdk-utils/percy-web/types.js +1 -0
  153. package/dist/tools/testmanagement-utils/create-testrun.d.ts +4 -4
  154. package/dist/tools/testmanagement-utils/update-testrun.d.ts +4 -4
  155. package/package.json +3 -2
  156. package/dist/tools/appautomate-utils/types.d.ts +0 -5
  157. package/dist/tools/sdk-utils/commands.js +0 -65
  158. package/dist/tools/sdk-utils/instructions.d.ts +0 -6
  159. package/dist/tools/sdk-utils/instructions.js +0 -99
  160. package/dist/tools/sdk-utils/percy/constants.d.ts +0 -3
  161. package/dist/tools/sdk-utils/percy/instructions.d.ts +0 -10
  162. package/dist/tools/sdk-utils/percy/types.d.ts +0 -5
  163. package/dist/tools/sdk-utils/types.d.ts +0 -40
  164. /package/dist/tools/{sdk-utils/percy → percy-snapshot-utils}/types.js +0 -0
@@ -0,0 +1,7 @@
1
+ import { ValidatedEnvironment } from "../../sdk-utils/common/device-validator.js";
2
+ export declare function generateAppBrowserStackYMLInstructions(config: {
3
+ validatedEnvironments?: ValidatedEnvironment[];
4
+ platforms?: string[];
5
+ testingFramework?: string;
6
+ projectName?: string;
7
+ }, username: string, accessKey: string, appPath?: string): string;
@@ -0,0 +1,70 @@
1
+ import { APP_DEVICE_CONFIGS, AppSDKSupportedTestingFrameworkEnum, DEFAULT_APP_PATH, createStep, } from "./index.js";
2
+ export function generateAppBrowserStackYMLInstructions(config, username, accessKey, appPath = DEFAULT_APP_PATH) {
3
+ if (config.testingFramework ===
4
+ AppSDKSupportedTestingFrameworkEnum.nightwatch ||
5
+ config.testingFramework ===
6
+ AppSDKSupportedTestingFrameworkEnum.webdriverio ||
7
+ config.testingFramework === AppSDKSupportedTestingFrameworkEnum.cucumberRuby) {
8
+ return "";
9
+ }
10
+ const platformConfigs = generatePlatformConfigs(config);
11
+ const projectName = config.projectName || "BrowserStack Sample";
12
+ const buildName = config.projectName
13
+ ? `${config.projectName}-AppAutomate-Build`
14
+ : "bstack-demo";
15
+ const configContent = `\`\`\`yaml
16
+ userName: ${username}
17
+ accessKey: ${accessKey}
18
+ app: ${appPath}
19
+ platforms:
20
+ ${platformConfigs}
21
+ parallelsPerPlatform: 1
22
+ browserstackLocal: true
23
+ // TODO: replace projectName and buildName according to actual project
24
+ projectName: ${projectName}
25
+ buildName: ${buildName}
26
+ debug: true
27
+ networkLogs: true
28
+ percy: false
29
+ percyCaptureMode: auto
30
+ accessibility: false
31
+ \`\`\`
32
+
33
+ **Important notes:**
34
+ - Replace \`app: ${appPath}\` with the path to your actual app file (e.g., \`./SampleApp.apk\` for Android or \`./SampleApp.ipa\` for iOS)
35
+ - You can upload your app using BrowserStack's App Upload API or manually through the dashboard
36
+ - Set \`browserstackLocal: true\` if you need to test with local/staging servers
37
+ - Adjust \`parallelsPerPlatform\` based on your subscription limits`;
38
+ const stepTitle = "Update browserstack.yml file with App Automate configuration:";
39
+ const stepDescription = `Create or update the browserstack.yml file in your project root with the following content:
40
+ ${configContent}`;
41
+ return createStep(stepTitle, stepDescription);
42
+ }
43
+ function generatePlatformConfigs(config) {
44
+ if (config.validatedEnvironments && config.validatedEnvironments.length > 0) {
45
+ return config.validatedEnvironments
46
+ .filter((env) => env.platform === "android" || env.platform === "ios")
47
+ .map((env) => {
48
+ return ` - platformName: ${env.platform}
49
+ deviceName: "${env.deviceName}"
50
+ platformVersion: "${env.osVersion}"`;
51
+ })
52
+ .join("\n");
53
+ }
54
+ else if (config.platforms && config.platforms.length > 0) {
55
+ return config.platforms
56
+ .map((platform) => {
57
+ const devices = APP_DEVICE_CONFIGS[platform];
58
+ if (!devices)
59
+ return "";
60
+ return devices
61
+ .map((device) => ` - platformName: ${platform}
62
+ deviceName: ${device.deviceName}
63
+ platformVersion: "${device.platformVersion}"`)
64
+ .join("\n");
65
+ })
66
+ .filter(Boolean)
67
+ .join("\n");
68
+ }
69
+ return "";
70
+ }
@@ -0,0 +1,23 @@
1
+ import { z } from "zod";
2
+ import { AppSDKSupportedFrameworkEnum, AppSDKSupportedTestingFrameworkEnum, AppSDKSupportedLanguageEnum, AppSDKSupportedPlatformEnum } from "./index.js";
3
+ export declare const APP_DEVICE_CONFIGS: {
4
+ android: {
5
+ deviceName: string;
6
+ platformVersion: string;
7
+ }[];
8
+ ios: {
9
+ deviceName: string;
10
+ platformVersion: string;
11
+ }[];
12
+ };
13
+ export declare const STEP_DELIMITER = "---STEP---";
14
+ export declare const DEFAULT_APP_PATH = "bs://sample.app";
15
+ export declare const SETUP_APP_AUTOMATE_DESCRIPTION = "Set up BrowserStack App Automate SDK integration for Appium-based mobile app testing. ONLY for Appium based framework . This tool configures SDK for various languages with appium. For pre-built Espresso or XCUITest test suites, use 'runAppTestsOnBrowserStack' instead.";
16
+ export declare const SETUP_APP_AUTOMATE_SCHEMA: {
17
+ detectedFramework: z.ZodNativeEnum<typeof AppSDKSupportedFrameworkEnum>;
18
+ detectedTestingFramework: z.ZodNativeEnum<typeof AppSDKSupportedTestingFrameworkEnum>;
19
+ detectedLanguage: z.ZodNativeEnum<typeof AppSDKSupportedLanguageEnum>;
20
+ devices: z.ZodDefault<z.ZodArray<z.ZodUnion<[z.ZodTuple<[z.ZodLiteral<AppSDKSupportedPlatformEnum.android>, z.ZodString, z.ZodString], null>, z.ZodTuple<[z.ZodLiteral<AppSDKSupportedPlatformEnum.ios>, z.ZodString, z.ZodString], null>]>, "many">>;
21
+ appPath: z.ZodString;
22
+ project: z.ZodDefault<z.ZodOptional<z.ZodString>>;
23
+ };
@@ -0,0 +1,64 @@
1
+ import { z } from "zod";
2
+ import { AppSDKSupportedFrameworkEnum, AppSDKSupportedTestingFrameworkEnum, AppSDKSupportedLanguageEnum, AppSDKSupportedPlatformEnum, } from "./index.js";
3
+ // App Automate specific device configurations
4
+ export const APP_DEVICE_CONFIGS = {
5
+ android: [
6
+ { deviceName: "Samsung Galaxy S22 Ultra", platformVersion: "12.0" },
7
+ { deviceName: "Google Pixel 7 Pro", platformVersion: "13.0" },
8
+ { deviceName: "OnePlus 9", platformVersion: "11.0" },
9
+ ],
10
+ ios: [
11
+ { deviceName: "iPhone 14", platformVersion: "16" },
12
+ { deviceName: "iPhone 13", platformVersion: "15" },
13
+ { deviceName: "iPad Air 4", platformVersion: "14" },
14
+ ],
15
+ };
16
+ // Step delimiter for parsing instructions
17
+ export const STEP_DELIMITER = "---STEP---";
18
+ // Default app path for examples
19
+ export const DEFAULT_APP_PATH = "bs://sample.app";
20
+ // Tool description and schema for setupBrowserStackAppAutomateTests
21
+ export const SETUP_APP_AUTOMATE_DESCRIPTION = "Set up BrowserStack App Automate SDK integration for Appium-based mobile app testing. ONLY for Appium based framework . This tool configures SDK for various languages with appium. For pre-built Espresso or XCUITest test suites, use 'runAppTestsOnBrowserStack' instead.";
22
+ export const SETUP_APP_AUTOMATE_SCHEMA = {
23
+ detectedFramework: z
24
+ .nativeEnum(AppSDKSupportedFrameworkEnum)
25
+ .describe("The mobile automation framework configured in the project. Example: 'appium'"),
26
+ detectedTestingFramework: z
27
+ .nativeEnum(AppSDKSupportedTestingFrameworkEnum)
28
+ .describe("The testing framework used in the project. Be precise with framework selection Example: 'testng', 'behave', 'pytest', 'robot'"),
29
+ detectedLanguage: z
30
+ .nativeEnum(AppSDKSupportedLanguageEnum)
31
+ .describe("The programming language used in the project. Supports Java and C#. Example: 'java', 'csharp'"),
32
+ devices: z
33
+ .array(z.union([
34
+ // Android: [android, deviceName, osVersion]
35
+ z.tuple([
36
+ z
37
+ .literal(AppSDKSupportedPlatformEnum.android)
38
+ .describe("Platform identifier: 'android'"),
39
+ z
40
+ .string()
41
+ .describe("Device name, e.g. 'Samsung Galaxy S24', 'Google Pixel 8'"),
42
+ z.string().describe("Android version, e.g. '14', '16', 'latest'"),
43
+ ]),
44
+ // iOS: [ios, deviceName, osVersion]
45
+ z.tuple([
46
+ z
47
+ .literal(AppSDKSupportedPlatformEnum.ios)
48
+ .describe("Platform identifier: 'ios'"),
49
+ z.string().describe("Device name, e.g. 'iPhone 15', 'iPhone 14 Pro'"),
50
+ z.string().describe("iOS version, e.g. '17', '16', 'latest'"),
51
+ ]),
52
+ ]))
53
+ .max(3)
54
+ .default([])
55
+ .describe("Tuples describing target mobile devices. Add device only when user asks explicitly for it. Defaults to [] . Example: [['android', 'Samsung Galaxy S24', '14'], ['ios', 'iPhone 15', '17']]"),
56
+ appPath: z
57
+ .string()
58
+ .describe("Path to the mobile app file (.apk for Android, .ipa for iOS). Can be a local file path or a BrowserStack app URL (bs://)"),
59
+ project: z
60
+ .string()
61
+ .optional()
62
+ .default("BStack-AppAutomate-Suite")
63
+ .describe("Project name for organizing test runs on BrowserStack."),
64
+ };
@@ -0,0 +1,8 @@
1
+ import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
2
+ export declare function formatFinalAppInstructions(formattedInstructions: string): CallToolResult;
3
+ export declare function createStep(title: string, content: string): string;
4
+ export declare function combineInstructions(...instructionParts: string[]): string;
5
+ export declare function formatEnvCommands(username: string, accessKey: string, isWindows: boolean): string;
6
+ export declare function createEnvStep(username: string, accessKey: string, isWindows: boolean, platformLabel: string, title?: string): string;
7
+ export declare function formatMultiLineCommand(command: string, isWindows?: boolean): string;
8
+ export declare function formatAppInstructionsWithNumbers(instructions: string): string;
@@ -0,0 +1,59 @@
1
+ import { STEP_DELIMITER } from "./constants.js";
2
+ export function formatFinalAppInstructions(formattedInstructions) {
3
+ const fullInstructions = `
4
+ ⚠️ IMPORTANT: DO NOT SKIP ANY STEP
5
+ All the setup steps described in this file MUST be executed regardless of any existing configuration or setup.
6
+ This ensures proper BrowserStack App Automate SDK setup.
7
+ Each step is compulsory and sequence needs to be maintained.
8
+
9
+ ${formattedInstructions}`;
10
+ return {
11
+ content: [
12
+ {
13
+ type: "text",
14
+ text: fullInstructions,
15
+ isError: false,
16
+ },
17
+ ],
18
+ };
19
+ }
20
+ export function createStep(title, content) {
21
+ return `${STEP_DELIMITER}
22
+ ${title}
23
+
24
+ ${content}`;
25
+ }
26
+ export function combineInstructions(...instructionParts) {
27
+ return instructionParts.filter(Boolean).join("\n\n");
28
+ }
29
+ export function formatEnvCommands(username, accessKey, isWindows) {
30
+ if (isWindows) {
31
+ return `\`\`\`cmd
32
+ setx BROWSERSTACK_USERNAME "${username}"
33
+ setx BROWSERSTACK_ACCESS_KEY "${accessKey}"
34
+ \`\`\``;
35
+ }
36
+ return `\`\`\`bash
37
+ export BROWSERSTACK_USERNAME=${username}
38
+ export BROWSERSTACK_ACCESS_KEY=${accessKey}
39
+ \`\`\``;
40
+ }
41
+ export function createEnvStep(username, accessKey, isWindows, platformLabel, title = "Set BrowserStack credentials as environment variables:") {
42
+ return createStep(title, `**${platformLabel}:**
43
+ ${formatEnvCommands(username, accessKey, isWindows)}`);
44
+ }
45
+ export function formatMultiLineCommand(command, isWindows = process.platform === "win32") {
46
+ if (isWindows) {
47
+ // For Windows, keep commands on single line
48
+ return command.replace(/\s*\\\s*\n\s*/g, " ");
49
+ }
50
+ return command;
51
+ }
52
+ export function formatAppInstructionsWithNumbers(instructions) {
53
+ const steps = instructions
54
+ .split(STEP_DELIMITER)
55
+ .filter((step) => step.trim());
56
+ return steps
57
+ .map((step, index) => `**Step ${index + 1}:**\n${step.trim()}`)
58
+ .join("\n\n");
59
+ }
@@ -0,0 +1,3 @@
1
+ import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
2
+ import { BrowserStackConfig } from "../../../lib/types.js";
3
+ export declare function setupAppAutomateHandler(rawInput: unknown, config: BrowserStackConfig): Promise<CallToolResult>;
@@ -0,0 +1,66 @@
1
+ import { z } from "zod";
2
+ import { getBrowserStackAuth } from "../../../lib/get-auth.js";
3
+ import { validateAppAutomateDevices } from "../../sdk-utils/common/device-validator.js";
4
+ import { getAppUploadInstruction, validateSupportforAppAutomate, } from "./utils.js";
5
+ import { getAppSDKPrefixCommand, generateAppBrowserStackYMLInstructions, } from "./index.js";
6
+ import { formatAppInstructionsWithNumbers, getAppInstructionsForProjectConfiguration, SETUP_APP_AUTOMATE_SCHEMA, } from "./index.js";
7
+ export async function setupAppAutomateHandler(rawInput, config) {
8
+ const input = z.object(SETUP_APP_AUTOMATE_SCHEMA).parse(rawInput);
9
+ const auth = getBrowserStackAuth(config);
10
+ const [username, accessKey] = auth.split(":");
11
+ const instructions = [];
12
+ // Use variables for all major input properties
13
+ const testingFramework = input.detectedTestingFramework;
14
+ const language = input.detectedLanguage;
15
+ const inputDevices = input.devices ?? [];
16
+ const appPath = input.appPath;
17
+ const framework = input.detectedFramework;
18
+ //Validating if supported framework or not
19
+ validateSupportforAppAutomate(framework, language, testingFramework);
20
+ // Use default mobile devices when array is empty
21
+ const devices = inputDevices.length === 0
22
+ ? [["android", "Samsung Galaxy S24", "latest"]]
23
+ : inputDevices;
24
+ // Validate devices against real BrowserStack device data
25
+ const validatedEnvironments = await validateAppAutomateDevices(devices);
26
+ // Extract platforms for backward compatibility (if needed)
27
+ const platforms = validatedEnvironments.map((env) => env.platform);
28
+ // Step 1: Generate SDK setup command
29
+ const sdkCommand = getAppSDKPrefixCommand(language, testingFramework, username, accessKey, appPath);
30
+ if (sdkCommand) {
31
+ instructions.push({ content: sdkCommand, type: "setup" });
32
+ }
33
+ // Step 2: Generate browserstack.yml configuration
34
+ const configInstructions = generateAppBrowserStackYMLInstructions({
35
+ validatedEnvironments,
36
+ platforms,
37
+ testingFramework,
38
+ projectName: input.project,
39
+ }, username, accessKey, appPath);
40
+ if (configInstructions) {
41
+ instructions.push({ content: configInstructions, type: "config" });
42
+ }
43
+ // Step 3: Generate app upload instruction
44
+ const appUploadInstruction = await getAppUploadInstruction(appPath, username, accessKey, testingFramework);
45
+ if (appUploadInstruction) {
46
+ instructions.push({ content: appUploadInstruction, type: "setup" });
47
+ }
48
+ // Step 4: Generate project configuration and run instructions
49
+ const projectInstructions = getAppInstructionsForProjectConfiguration(framework, testingFramework, language);
50
+ if (projectInstructions) {
51
+ instructions.push({ content: projectInstructions, type: "run" });
52
+ }
53
+ const combinedInstructions = instructions
54
+ .map((instruction) => instruction.content)
55
+ .join("\n\n");
56
+ return {
57
+ content: [
58
+ {
59
+ type: "text",
60
+ text: formatAppInstructionsWithNumbers(combinedInstructions),
61
+ isError: false,
62
+ },
63
+ ],
64
+ isError: false,
65
+ };
66
+ }
@@ -0,0 +1,7 @@
1
+ export { getAppSDKPrefixCommand, getAppInstructionsForProjectConfiguration, } from "./instructions.js";
2
+ export { generateAppBrowserStackYMLInstructions } from "./config-generator.js";
3
+ export * from "./types.js";
4
+ export * from "./constants.js";
5
+ export * from "./utils.js";
6
+ export * from "./instructions.js";
7
+ export * from "./formatter.js";
@@ -0,0 +1,8 @@
1
+ // Barrel exports for App BrowserStack module
2
+ export { getAppSDKPrefixCommand, getAppInstructionsForProjectConfiguration, } from "./instructions.js";
3
+ export { generateAppBrowserStackYMLInstructions } from "./config-generator.js";
4
+ export * from "./types.js";
5
+ export * from "./constants.js";
6
+ export * from "./utils.js";
7
+ export * from "./instructions.js";
8
+ export * from "./formatter.js";
@@ -0,0 +1,3 @@
1
+ import { AppSDKSupportedLanguage, AppSDKSupportedTestingFramework } from "./index.js";
2
+ export declare function getAppInstructionsForProjectConfiguration(framework: string, testingFramework: AppSDKSupportedTestingFramework, language: AppSDKSupportedLanguage): string;
3
+ export declare function getAppSDKPrefixCommand(language: AppSDKSupportedLanguage, testingFramework: string, username: string, accessKey: string, appPath?: string): string;
@@ -0,0 +1,47 @@
1
+ // Language-specific instruction imports
2
+ import { getJavaAppInstructions } from "./languages/java.js";
3
+ import { getCSharpAppInstructions } from "./languages/csharp.js";
4
+ import { getNodejsAppInstructions } from "./languages/nodejs.js";
5
+ import { getPythonAppInstructions } from "./languages/python.js";
6
+ import { getRubyAppInstructions } from "./languages/ruby.js";
7
+ // Language-specific command imports
8
+ import { getCSharpSDKCommand } from "./languages/csharp.js";
9
+ import { getJavaSDKCommand } from "./languages/java.js";
10
+ import { getNodejsSDKCommand } from "./languages/nodejs.js";
11
+ import { getPythonSDKCommand } from "./languages/python.js";
12
+ import { getRubySDKCommand } from "./languages/ruby.js";
13
+ export function getAppInstructionsForProjectConfiguration(framework, testingFramework, language) {
14
+ if (!framework || !testingFramework || !language) {
15
+ return "";
16
+ }
17
+ switch (language) {
18
+ case "java":
19
+ return getJavaAppInstructions();
20
+ case "nodejs":
21
+ return getNodejsAppInstructions(testingFramework);
22
+ case "python":
23
+ return getPythonAppInstructions(testingFramework);
24
+ case "ruby":
25
+ return getRubyAppInstructions();
26
+ case "csharp":
27
+ return getCSharpAppInstructions();
28
+ default:
29
+ return "";
30
+ }
31
+ }
32
+ export function getAppSDKPrefixCommand(language, testingFramework, username, accessKey, appPath) {
33
+ switch (language) {
34
+ case "csharp":
35
+ return getCSharpSDKCommand(username, accessKey);
36
+ case "java":
37
+ return getJavaSDKCommand(testingFramework, username, accessKey, appPath);
38
+ case "nodejs":
39
+ return getNodejsSDKCommand(testingFramework, username, accessKey);
40
+ case "python":
41
+ return getPythonSDKCommand(testingFramework, username, accessKey);
42
+ case "ruby":
43
+ return getRubySDKCommand(testingFramework, username, accessKey);
44
+ default:
45
+ return "";
46
+ }
47
+ }
@@ -0,0 +1,2 @@
1
+ export declare function getCSharpAppInstructions(): string;
2
+ export declare function getCSharpSDKCommand(username: string, accessKey: string): string;
@@ -0,0 +1,78 @@
1
+ // C# instructions and commands for App SDK utilities
2
+ import { PLATFORM_UTILS, createStep, createEnvStep, combineInstructions, } from "../index.js";
3
+ export function getCSharpAppInstructions() {
4
+ const { isWindows, isAppleSilicon, getPlatformLabel } = PLATFORM_UTILS;
5
+ let runCommand = "";
6
+ if (isWindows) {
7
+ runCommand = `\`\`\`cmd
8
+ dotnet build
9
+ dotnet test --filter <EXPRESSION> [other_args]
10
+ \`\`\``;
11
+ }
12
+ else if (isAppleSilicon) {
13
+ runCommand = `\`\`\`bash
14
+ dotnet build
15
+ dotnet test --filter <EXPRESSION> [other_args]
16
+ \`\`\`
17
+
18
+ **Did not set the alias?**
19
+ Use the absolute path to the dotnet installation to run your tests on Mac computers with Apple silicon chips:
20
+ \`\`\`bash
21
+ </absolute/path/to/location/of/dotnet/>/dotnet test
22
+ \`\`\``;
23
+ }
24
+ else {
25
+ runCommand = `\`\`\`bash
26
+ dotnet build
27
+ dotnet test --filter <EXPRESSION> [other_args]
28
+ \`\`\``;
29
+ }
30
+ const runStep = createStep("Run your C# test suite:", `**${getPlatformLabel()}:**
31
+ ${runCommand}
32
+
33
+ **Debug Guidelines:**
34
+ If you encounter the error: java.lang.IllegalArgumentException: Multiple entries with the same key,
35
+ __Resolution:__
36
+ - The app capability should only be set in one place: browserstack.yml.
37
+ - Remove or comment out any code or configuration in your test setup (e.g., step definitions, runners, or capabilities setup) that sets the app path directly.`);
38
+ return runStep;
39
+ }
40
+ export function getCSharpSDKCommand(username, accessKey) {
41
+ const { isWindows = false, isAppleSilicon = false, getPlatformLabel = () => "Unknown", } = PLATFORM_UTILS || {};
42
+ if (!PLATFORM_UTILS) {
43
+ console.warn("PLATFORM_UTILS is undefined. Defaulting platform values.");
44
+ }
45
+ const envStep = createEnvStep(username, accessKey, isWindows, getPlatformLabel());
46
+ const installCommands = isWindows
47
+ ? `\`\`\`cmd
48
+ dotnet add package BrowserStack.TestAdapter
49
+ dotnet build
50
+ dotnet browserstack-sdk setup --userName "${username}" --accessKey "${accessKey}"
51
+ \`\`\``
52
+ : `\`\`\`bash
53
+ dotnet add package BrowserStack.TestAdapter
54
+ dotnet build
55
+ dotnet browserstack-sdk setup --userName "${username}" --accessKey "${accessKey}"
56
+ \`\`\``;
57
+ const installStep = createStep("Install BrowserStack SDK", `Run the following command to install the BrowserStack SDK and create a browserstack.yml file in the root directory of your project:
58
+
59
+ **${getPlatformLabel()}:**
60
+ ${installCommands}`);
61
+ const appleSiliconNote = isAppleSilicon
62
+ ? createStep("[Only for Macs with Apple silicon] Install dotnet x64 on MacOS", `If you are using a Mac computer with Apple silicon chip (M1 or M2) architecture, use the given command:
63
+
64
+ \`\`\`bash
65
+ cd #(project folder Android or iOS)
66
+ dotnet browserstack-sdk setup-dotnet --dotnet-path "<path>" --dotnet-version "<version>"
67
+ \`\`\`
68
+
69
+ - \`<path>\` - Mention the absolute path to the directory where you want to save dotnet x64
70
+ - \`<version>\` - Mention the dotnet version which you want to use to run tests
71
+
72
+ This command performs the following functions:
73
+ - Installs dotnet x64
74
+ - Installs the required version of dotnet x64 at an appropriate path
75
+ - Sets alias for the dotnet installation location on confirmation (enter y option)`)
76
+ : "";
77
+ return combineInstructions(envStep, installStep, appleSiliconNote);
78
+ }
@@ -0,0 +1,10 @@
1
+ export declare const MAVEN_ARCHETYPE_GROUP_ID = "com.browserstack";
2
+ export declare const MAVEN_ARCHETYPE_ARTIFACT_ID = "junit-archetype-integrate";
3
+ export declare const MAVEN_ARCHETYPE_VERSION = "1.0";
4
+ export declare const JAVA_APP_FRAMEWORK_VERSION_MAP: Record<string, string>;
5
+ export declare const JAVA_APP_FRAMEWORK_MAP: Record<string, string>;
6
+ export declare const GRADLE_APP_SETUP_INSTRUCTIONS = "\n**For Gradle setup:**\n1. Add browserstack-java-sdk to dependencies:\n compileOnly 'com.browserstack:browserstack-java-sdk:latest.release'\n\n2. Add browserstackSDK path variable:\n def browserstackSDKArtifact = configurations.compileClasspath.resolvedConfiguration.resolvedArtifacts.find { it.name == 'browserstack-java-sdk' }\n\n3. Add javaagent to gradle tasks:\n jvmArgs \"-javaagent:${browserstackSDKArtifact.file}\"\n";
7
+ export declare function getJavaAppInstructions(): string;
8
+ export declare function getJavaAppFrameworkForMaven(framework: string): string;
9
+ export declare function getJavaAppFrameworkVersion(framework: string): string;
10
+ export declare function getJavaSDKCommand(framework: string, username: string, accessKey: string, appPath?: string): string;
@@ -0,0 +1,121 @@
1
+ // Java instructions and commands for App SDK utilities
2
+ import { createStep, combineInstructions, createEnvStep, PLATFORM_UTILS, } from "../index.js";
3
+ // Java-specific constants and mappings
4
+ export const MAVEN_ARCHETYPE_GROUP_ID = "com.browserstack";
5
+ export const MAVEN_ARCHETYPE_ARTIFACT_ID = "junit-archetype-integrate";
6
+ export const MAVEN_ARCHETYPE_VERSION = "1.0";
7
+ // Version mapping for different frameworks
8
+ export const JAVA_APP_FRAMEWORK_VERSION_MAP = {
9
+ testng: "1.4",
10
+ selenide: "1.4",
11
+ junit5: "1.0",
12
+ junit4: "1.0",
13
+ jbehave: "1.0",
14
+ cucumberTestng: "1.0",
15
+ cucumberJunit4: "1.0",
16
+ cucumberJunit5: "1.0",
17
+ cucumber: "1.0",
18
+ serenity: "1.0",
19
+ };
20
+ // Framework mapping for Java Maven archetype generation for App Automate
21
+ export const JAVA_APP_FRAMEWORK_MAP = {
22
+ testng: "testng-archetype-integrate",
23
+ junit5: "browserstack-sdk-archetype-integrate",
24
+ selenide: "selenide-archetype-integrate",
25
+ jbehave: "browserstack-sdk-archetype-integrate",
26
+ junit4: "browserstack-sdk-archetype-integrate",
27
+ cucumberTestng: "browserstack-sdk-archetype-integrate",
28
+ cucumberJunit4: "browserstack-sdk-archetype-integrate",
29
+ cucumberJunit5: "browserstack-sdk-archetype-integrate",
30
+ cucumber: "browserstack-sdk-archetype-integrate",
31
+ serenity: "browserstack-sdk-archetype-integrate",
32
+ };
33
+ // Common Gradle setup instructions for App Automate (platform-independent)
34
+ export const GRADLE_APP_SETUP_INSTRUCTIONS = `
35
+ **For Gradle setup:**
36
+ 1. Add browserstack-java-sdk to dependencies:
37
+ compileOnly 'com.browserstack:browserstack-java-sdk:latest.release'
38
+
39
+ 2. Add browserstackSDK path variable:
40
+ def browserstackSDKArtifact = configurations.compileClasspath.resolvedConfiguration.resolvedArtifacts.find { it.name == 'browserstack-java-sdk' }
41
+
42
+ 3. Add javaagent to gradle tasks:
43
+ jvmArgs "-javaagent:\${browserstackSDKArtifact.file}"
44
+ `;
45
+ export function getJavaAppInstructions() {
46
+ const baseRunStep = createStep("Run your App Automate test suite:", `\`\`\`bash
47
+ mvn test
48
+ \`\`\``);
49
+ return baseRunStep;
50
+ }
51
+ export function getJavaAppFrameworkForMaven(framework) {
52
+ return JAVA_APP_FRAMEWORK_MAP[framework] || framework;
53
+ }
54
+ export function getJavaAppFrameworkVersion(framework) {
55
+ return JAVA_APP_FRAMEWORK_VERSION_MAP[framework] || MAVEN_ARCHETYPE_VERSION;
56
+ }
57
+ function getMavenCommandForWindows(framework, mavenFramework, version, username, accessKey, appPath) {
58
+ let command = `mvn archetype:generate -B ` +
59
+ `-DarchetypeGroupId="${MAVEN_ARCHETYPE_GROUP_ID}" ` +
60
+ `-DarchetypeArtifactId="${mavenFramework}" ` +
61
+ `-DarchetypeVersion="${version}" ` +
62
+ `-DgroupId="${MAVEN_ARCHETYPE_GROUP_ID}" ` +
63
+ `-DartifactId="${mavenFramework}" ` +
64
+ `-Dversion="${version}" ` +
65
+ `-DBROWSERSTACK_USERNAME="${username}" ` +
66
+ `-DBROWSERSTACK_ACCESS_KEY="${accessKey}"`;
67
+ // Add framework parameter for browserstack-sdk-archetype-integrate
68
+ if (mavenFramework === "browserstack-sdk-archetype-integrate") {
69
+ command += ` -DBROWSERSTACK_FRAMEWORK="${framework}"`;
70
+ }
71
+ // Add app path if provided
72
+ if (appPath) {
73
+ command += ` -DBROWSERSTACK_APP="${appPath}"`;
74
+ }
75
+ return command;
76
+ }
77
+ function getMavenCommandForUnix(framework, mavenFramework, version, username, accessKey, appPath) {
78
+ let command = `mvn archetype:generate -B ` +
79
+ `-DarchetypeGroupId="${MAVEN_ARCHETYPE_GROUP_ID}" ` +
80
+ `-DarchetypeArtifactId="${mavenFramework}" ` +
81
+ `-DarchetypeVersion="${version}" ` +
82
+ `-DgroupId="${MAVEN_ARCHETYPE_GROUP_ID}" ` +
83
+ `-DartifactId="${mavenFramework}" ` +
84
+ `-Dversion="${version}" ` +
85
+ `-DBROWSERSTACK_USERNAME="${username}" ` +
86
+ `-DBROWSERSTACK_ACCESS_KEY="${accessKey}"`;
87
+ // Add framework parameter for browserstack-sdk-archetype-integrate
88
+ if (mavenFramework === "browserstack-sdk-archetype-integrate") {
89
+ command += ` -DBROWSERSTACK_FRAMEWORK="${framework}"`;
90
+ }
91
+ // Add app path if provided
92
+ if (appPath) {
93
+ command += ` -DBROWSERSTACK_APP="${appPath}"`;
94
+ }
95
+ return command;
96
+ }
97
+ export function getJavaSDKCommand(framework, username, accessKey, appPath) {
98
+ const { isWindows = false, getPlatformLabel } = PLATFORM_UTILS || {};
99
+ const mavenFramework = getJavaAppFrameworkForMaven(framework);
100
+ const version = getJavaAppFrameworkVersion(framework);
101
+ let mavenCommand;
102
+ if (isWindows) {
103
+ mavenCommand = getMavenCommandForWindows(framework, mavenFramework, version, username, accessKey, appPath);
104
+ }
105
+ else {
106
+ mavenCommand = getMavenCommandForUnix(framework, mavenFramework, version, username, accessKey, appPath);
107
+ }
108
+ const envStep = createEnvStep(username, accessKey, isWindows, getPlatformLabel());
109
+ const mavenStep = createStep("Install BrowserStack SDK using Maven Archetype for App Automate", `Maven command for ${framework} (${getPlatformLabel()}):
110
+ \`\`\`bash
111
+ ${mavenCommand}
112
+ \`\`\`
113
+
114
+ Alternative setup for Gradle users:
115
+ ${GRADLE_APP_SETUP_INSTRUCTIONS}`);
116
+ const argsLineStep = createStep("Verifying dependency and argsLine", `Verify browserstack-java-sdk with LATEST is added as dependency and add this line in pom.xml if not added:
117
+ \`\`\`xml
118
+ <argLine>-javaagent:"\${com.browserstack:browserstack-java-sdk:jar}"</argLine>
119
+ \`\`\``);
120
+ return combineInstructions(envStep, mavenStep, argsLineStep);
121
+ }
@@ -0,0 +1,3 @@
1
+ import { AppSDKSupportedTestingFramework } from "../index.js";
2
+ export declare function getNodejsSDKCommand(testingFramework: string, username: string, accessKey: string): string;
3
+ export declare function getNodejsAppInstructions(testingFramework: AppSDKSupportedTestingFramework): string;