@browserstack/mcp-server 1.2.31 → 1.2.33-beta.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.
Files changed (42) hide show
  1. package/dist/tools/accessibility.js +3 -3
  2. package/dist/tools/accessiblity-utils/auth-config.d.ts +11 -0
  3. package/dist/tools/accessiblity-utils/auth-config.js +19 -2
  4. package/dist/tools/appautomate-utils/appium-sdk/config-generator.d.ts +1 -1
  5. package/dist/tools/appautomate-utils/appium-sdk/config-generator.js +4 -4
  6. package/dist/tools/appautomate-utils/appium-sdk/constants.d.ts +2 -1
  7. package/dist/tools/appautomate-utils/appium-sdk/constants.js +5 -1
  8. package/dist/tools/appautomate-utils/appium-sdk/formatter.d.ts +2 -2
  9. package/dist/tools/appautomate-utils/appium-sdk/formatter.js +8 -8
  10. package/dist/tools/appautomate-utils/appium-sdk/handler.js +10 -4
  11. package/dist/tools/appautomate-utils/appium-sdk/instructions.d.ts +1 -1
  12. package/dist/tools/appautomate-utils/appium-sdk/instructions.js +6 -6
  13. package/dist/tools/appautomate-utils/appium-sdk/languages/csharp.d.ts +1 -1
  14. package/dist/tools/appautomate-utils/appium-sdk/languages/csharp.js +5 -5
  15. package/dist/tools/appautomate-utils/appium-sdk/languages/java.d.ts +1 -1
  16. package/dist/tools/appautomate-utils/appium-sdk/languages/java.js +11 -11
  17. package/dist/tools/appautomate-utils/appium-sdk/languages/nodejs.d.ts +1 -1
  18. package/dist/tools/appautomate-utils/appium-sdk/languages/nodejs.js +23 -23
  19. package/dist/tools/appautomate-utils/appium-sdk/languages/python.d.ts +1 -1
  20. package/dist/tools/appautomate-utils/appium-sdk/languages/python.js +11 -11
  21. package/dist/tools/appautomate-utils/appium-sdk/languages/ruby.d.ts +1 -1
  22. package/dist/tools/appautomate-utils/appium-sdk/languages/ruby.js +7 -4
  23. package/dist/tools/sdk-utils/bstack/commands.d.ts +1 -1
  24. package/dist/tools/sdk-utils/bstack/commands.js +14 -14
  25. package/dist/tools/sdk-utils/bstack/configUtils.d.ts +1 -2
  26. package/dist/tools/sdk-utils/bstack/configUtils.js +3 -7
  27. package/dist/tools/sdk-utils/bstack/constants.d.ts +10 -10
  28. package/dist/tools/sdk-utils/bstack/constants.js +27 -27
  29. package/dist/tools/sdk-utils/bstack/sdkHandler.js +17 -9
  30. package/dist/tools/sdk-utils/common/credentials.d.ts +3 -0
  31. package/dist/tools/sdk-utils/common/credentials.js +11 -0
  32. package/dist/tools/sdk-utils/common/instructionUtils.d.ts +1 -1
  33. package/dist/tools/sdk-utils/common/instructionUtils.js +2 -2
  34. package/dist/tools/sdk-utils/common/types.d.ts +1 -1
  35. package/dist/tools/sdk-utils/handler.js +1 -1
  36. package/dist/tools/sdk-utils/percy-bstack/handler.d.ts +1 -2
  37. package/dist/tools/sdk-utils/percy-bstack/handler.js +13 -9
  38. package/dist/tools/testmanagement-utils/create-testcase.js +8 -0
  39. package/dist/tools/testmanagement-utils/rich-text.d.ts +5 -0
  40. package/dist/tools/testmanagement-utils/rich-text.js +22 -0
  41. package/dist/tools/testmanagement-utils/update-testcase.js +4 -3
  42. package/package.json +1 -1
@@ -10,7 +10,7 @@ const JAVA_FRAMEWORK_MAP = {
10
10
  cucumber: "cucumber-testng",
11
11
  };
12
12
  // Template for Node.js SDK setup instructions
13
- const NODEJS_SDK_INSTRUCTIONS = (username, accessKey) => `---STEP---
13
+ const NODEJS_SDK_INSTRUCTIONS = () => `---STEP---
14
14
  Install BrowserStack Node SDK using command:
15
15
  \`\`\`bash
16
16
  npm i -D browserstack-node-sdk@latest
@@ -18,7 +18,7 @@ npm i -D browserstack-node-sdk@latest
18
18
  ---STEP---
19
19
  Run the following command to setup browserstack sdk:
20
20
  \`\`\`bash
21
- npx browserstack-node-sdk setup --username ${username} --key ${accessKey}
21
+ npx browserstack-node-sdk setup --username "<your_browserstack_username>" --key "<your_browserstack_access_key>"
22
22
  \`\`\``;
23
23
  // Template for Gradle setup instructions (platform-independent)
24
24
  const GRADLE_SETUP_INSTRUCTIONS = `
@@ -33,7 +33,7 @@ const GRADLE_SETUP_INSTRUCTIONS = `
33
33
  jvmArgs "-javaagent:\${browserstackSDKArtifact.file}"
34
34
  `;
35
35
  // Generates Maven archetype command for Windows platform
36
- function getMavenCommandForWindows(username, accessKey, mavenFramework) {
36
+ function getMavenCommandForWindows(mavenFramework) {
37
37
  return (`mvn archetype:generate -B ` +
38
38
  `-DarchetypeGroupId="${MAVEN_ARCHETYPE_GROUP_ID}" ` +
39
39
  `-DarchetypeArtifactId="${MAVEN_ARCHETYPE_ARTIFACT_ID}" ` +
@@ -41,27 +41,27 @@ function getMavenCommandForWindows(username, accessKey, mavenFramework) {
41
41
  `-DgroupId="${MAVEN_ARCHETYPE_GROUP_ID}" ` +
42
42
  `-DartifactId="${MAVEN_ARCHETYPE_ARTIFACT_ID}" ` +
43
43
  `-Dversion="${MAVEN_ARCHETYPE_VERSION}" ` +
44
- `-DBROWSERSTACK_USERNAME="${username}" ` +
45
- `-DBROWSERSTACK_ACCESS_KEY="${accessKey}" ` +
44
+ `-DBROWSERSTACK_USERNAME="<your_browserstack_username>" ` +
45
+ `-DBROWSERSTACK_ACCESS_KEY="<your_browserstack_access_key>" ` +
46
46
  `-DBROWSERSTACK_FRAMEWORK="${mavenFramework}"`);
47
47
  }
48
48
  // Generates Maven archetype command for Unix-like platforms (macOS/Linux)
49
- function getMavenCommandForUnix(username, accessKey, mavenFramework) {
49
+ function getMavenCommandForUnix(mavenFramework) {
50
50
  return `mvn archetype:generate -B -DarchetypeGroupId=${MAVEN_ARCHETYPE_GROUP_ID} \\
51
51
  -DarchetypeArtifactId=${MAVEN_ARCHETYPE_ARTIFACT_ID} -DarchetypeVersion=${MAVEN_ARCHETYPE_VERSION} \\
52
52
  -DgroupId=${MAVEN_ARCHETYPE_GROUP_ID} -DartifactId=${MAVEN_ARCHETYPE_ARTIFACT_ID} -Dversion=${MAVEN_ARCHETYPE_VERSION} \\
53
- -DBROWSERSTACK_USERNAME="${username}" \\
54
- -DBROWSERSTACK_ACCESS_KEY="${accessKey}" \\
53
+ -DBROWSERSTACK_USERNAME="<your_browserstack_username>" \\
54
+ -DBROWSERSTACK_ACCESS_KEY="<your_browserstack_access_key>" \\
55
55
  -DBROWSERSTACK_FRAMEWORK="${mavenFramework}"`;
56
56
  }
57
57
  // Generates Java SDK setup instructions with Maven/Gradle options
58
- function getJavaSDKInstructions(framework, username, accessKey) {
58
+ function getJavaSDKInstructions(framework) {
59
59
  const mavenFramework = getJavaFrameworkForMaven(framework);
60
60
  const isWindows = process.platform === "win32";
61
61
  const platformLabel = isWindows ? "Windows" : "macOS/Linux";
62
62
  const mavenCommand = isWindows
63
- ? getMavenCommandForWindows(username, accessKey, mavenFramework)
64
- : getMavenCommandForUnix(username, accessKey, mavenFramework);
63
+ ? getMavenCommandForWindows(mavenFramework)
64
+ : getMavenCommandForUnix(mavenFramework);
65
65
  return `---STEP---
66
66
  Install BrowserStack Java SDK
67
67
 
@@ -73,12 +73,12 @@ Alternative setup for Gradle users:
73
73
  ${GRADLE_SETUP_INSTRUCTIONS}`;
74
74
  }
75
75
  // Main function to get SDK setup commands based on language and framework
76
- export function getSDKPrefixCommand(language, framework, username, accessKey) {
76
+ export function getSDKPrefixCommand(language, framework) {
77
77
  switch (language) {
78
78
  case "nodejs":
79
- return NODEJS_SDK_INSTRUCTIONS(username, accessKey);
79
+ return NODEJS_SDK_INSTRUCTIONS();
80
80
  case "java":
81
- return getJavaSDKInstructions(framework, username, accessKey);
81
+ return getJavaSDKInstructions(framework);
82
82
  default:
83
83
  return "";
84
84
  }
@@ -1,8 +1,7 @@
1
1
  import { ValidatedEnvironment } from "../common/device-validator.js";
2
- import { BrowserStackConfig } from "../../../lib/types.js";
3
2
  export declare function generateBrowserStackYMLInstructions(config: {
4
3
  validatedEnvironments?: ValidatedEnvironment[];
5
4
  platforms?: string[];
6
5
  enablePercy?: boolean;
7
6
  projectName: string;
8
- }, browserStackConfig: BrowserStackConfig): string;
7
+ }): string;
@@ -1,10 +1,6 @@
1
- import { getBrowserStackAuth } from "../../../lib/get-auth.js";
2
- export function generateBrowserStackYMLInstructions(config, browserStackConfig) {
1
+ export function generateBrowserStackYMLInstructions(config) {
3
2
  const enablePercy = config.enablePercy || false;
4
3
  const projectName = config.projectName || "BrowserStack Automate Build";
5
- // Get credentials from config
6
- const authString = getBrowserStackAuth(browserStackConfig);
7
- const [username, accessKey] = authString.split(":");
8
4
  // Generate platform configurations using the utility function
9
5
  const platformConfigs = generatePlatformConfigs(config);
10
6
  const stepTitle = "Create a browserstack.yml file in the project root with your validated device configurations:If already exists, update it with the following content for devices and project details.";
@@ -14,8 +10,8 @@ export function generateBrowserStackYMLInstructions(config, browserStackConfig)
14
10
  # BrowserStack Reporting
15
11
  # ======================
16
12
 
17
- userName: ${username}
18
- accessKey: ${accessKey}
13
+ userName: <your_browserstack_username>
14
+ accessKey: <your_browserstack_access_key>
19
15
 
20
16
  # TODO: Replace these sample values with your actual project details
21
17
  projectName: ${projectName}
@@ -6,52 +6,52 @@ export declare const pythonInstructions: () => {
6
6
  setup: string;
7
7
  run: string;
8
8
  };
9
- export declare const generatePythonFrameworkInstructions: (framework: string) => (username: string, accessKey: string) => {
9
+ export declare const generatePythonFrameworkInstructions: (framework: string) => () => {
10
10
  setup: string;
11
11
  run: string;
12
12
  };
13
- export declare const robotInstructions: (username: string, accessKey: string) => {
13
+ export declare const robotInstructions: () => {
14
14
  setup: string;
15
15
  run: string;
16
16
  };
17
- export declare const behaveInstructions: (username: string, accessKey: string) => {
17
+ export declare const behaveInstructions: () => {
18
18
  setup: string;
19
19
  run: string;
20
20
  };
21
- export declare const pytestInstructions: (username: string, accessKey: string) => {
21
+ export declare const pytestInstructions: () => {
22
22
  setup: string;
23
23
  run: string;
24
24
  };
25
- export declare const javaInstructions: (username: string, accessKey: string) => {
25
+ export declare const javaInstructions: () => {
26
26
  setup: string;
27
27
  run: string;
28
28
  };
29
29
  /**
30
30
  * ---------- CSharp INSTRUCTIONS ----------
31
31
  */
32
- export declare const csharpCommonInstructions: (username: string, accessKey: string) => {
32
+ export declare const csharpCommonInstructions: () => {
33
33
  setup: string;
34
34
  run: string;
35
35
  };
36
- export declare const csharpPlaywrightCommonInstructions: (username: string, accessKey: string) => {
36
+ export declare const csharpPlaywrightCommonInstructions: () => {
37
37
  setup: string;
38
38
  run: string;
39
39
  };
40
40
  /**
41
41
  * ---------- NODEJS INSTRUCTIONS ----------
42
42
  */
43
- export declare const nodejsInstructions: (username: string, accessKey: string) => {
43
+ export declare const nodejsInstructions: () => {
44
44
  setup: string;
45
45
  run: string;
46
46
  };
47
47
  /**
48
48
  * ---------- EXPORT CONFIG ----------
49
49
  */
50
- export declare const webdriverioInstructions: (username: string, accessKey: string) => {
50
+ export declare const webdriverioInstructions: () => {
51
51
  setup: string;
52
52
  run: string;
53
53
  };
54
- export declare const cypressInstructions: (username: string, accessKey: string) => {
54
+ export declare const cypressInstructions: () => {
55
55
  setup: string;
56
56
  run: string;
57
57
  };
@@ -25,7 +25,7 @@ browserstack-sdk pytest <path-to-test-directory>
25
25
  `;
26
26
  return { setup, run };
27
27
  };
28
- export const generatePythonFrameworkInstructions = (framework) => (username, accessKey) => {
28
+ export const generatePythonFrameworkInstructions = (framework) => () => {
29
29
  const setup = `
30
30
  ---STEP---
31
31
 
@@ -39,7 +39,7 @@ python3 -m pip install browserstack-sdk
39
39
 
40
40
  Setup the BrowserStack SDK with framework-specific configuration:
41
41
  \`\`\`bash
42
- browserstack-sdk setup --framework "${framework}" --username "${username}" --key "${accessKey}"
42
+ browserstack-sdk setup --framework "${framework}" --username "<your_browserstack_username>" --key "<your_browserstack_access_key>"
43
43
  \`\`\`
44
44
  `;
45
45
  const run = `
@@ -59,7 +59,7 @@ export const pytestInstructions = generatePythonFrameworkInstructions("pytest");
59
59
  * ---------- JAVA INSTRUCTIONS ----------
60
60
  */
61
61
  const argsInstruction = '<argLine>-javaagent:"${com.browserstack:browserstack-java-sdk:jar}"</argLine>';
62
- export const javaInstructions = (username, accessKey) => {
62
+ export const javaInstructions = () => {
63
63
  const setup = `
64
64
  ---STEP---
65
65
 
@@ -86,8 +86,8 @@ dependencies {
86
86
 
87
87
  Export your BrowserStack credentials as environment variables:
88
88
  \`\`\`bash
89
- export BROWSERSTACK_USERNAME=${username}
90
- export BROWSERSTACK_ACCESS_KEY=${accessKey}
89
+ export BROWSERSTACK_USERNAME="<your_browserstack_username>"
90
+ export BROWSERSTACK_ACCESS_KEY="<your_browserstack_access_key>"
91
91
  \`\`\`
92
92
  `;
93
93
  const run = `
@@ -108,7 +108,7 @@ gradle clean test
108
108
  /**
109
109
  * ---------- CSharp INSTRUCTIONS ----------
110
110
  */
111
- export const csharpCommonInstructions = (username, accessKey) => {
111
+ export const csharpCommonInstructions = () => {
112
112
  const setup = `
113
113
  ---STEP---
114
114
 
@@ -128,7 +128,7 @@ dotnet build
128
128
 
129
129
  Set up BrowserStack SDK with your credentials:
130
130
  \`\`\`bash
131
- dotnet browserstack-sdk setup --userName ${username} --accessKey ${accessKey}
131
+ dotnet browserstack-sdk setup --userName "<your_browserstack_username>" --accessKey "<your_browserstack_access_key>"
132
132
  \`\`\`
133
133
 
134
134
  ---STEP---
@@ -174,7 +174,7 @@ Run the tests:
174
174
  `;
175
175
  return { setup, run };
176
176
  };
177
- export const csharpPlaywrightCommonInstructions = (username, accessKey) => {
177
+ export const csharpPlaywrightCommonInstructions = () => {
178
178
  const setup = `
179
179
  ---STEP---
180
180
 
@@ -194,7 +194,7 @@ dotnet build
194
194
 
195
195
  Set up BrowserStack SDK with your credentials:
196
196
  \`\`\`bash
197
- dotnet browserstack-sdk setup --userName ${username} --accessKey ${accessKey}
197
+ dotnet browserstack-sdk setup --userName "<your_browserstack_username>" --accessKey "<your_browserstack_access_key>"
198
198
  \`\`\`
199
199
 
200
200
  ---STEP---
@@ -256,7 +256,7 @@ Run the tests:
256
256
  /**
257
257
  * ---------- NODEJS INSTRUCTIONS ----------
258
258
  */
259
- export const nodejsInstructions = (username, accessKey) => {
259
+ export const nodejsInstructions = () => {
260
260
  const setup = `
261
261
  ---STEP---
262
262
 
@@ -285,8 +285,8 @@ Example :
285
285
  Export BrowserStack credentials as environment variables:
286
286
  Set the following environment variables before running tests.
287
287
  \`\`\`bash
288
- export BROWSERSTACK_USERNAME=${username}
289
- export BROWSERSTACK_ACCESS_KEY=${accessKey}
288
+ export BROWSERSTACK_USERNAME="<your_browserstack_username>"
289
+ export BROWSERSTACK_ACCESS_KEY="<your_browserstack_access_key>"
290
290
  \`\`\`
291
291
 
292
292
  ---STEP---
@@ -306,7 +306,7 @@ npm run test:browserstack
306
306
  /**
307
307
  * ---------- EXPORT CONFIG ----------
308
308
  */
309
- export const webdriverioInstructions = (username, accessKey) => {
309
+ export const webdriverioInstructions = () => {
310
310
  const setup = `
311
311
  ---STEP---
312
312
 
@@ -315,14 +315,14 @@ Export your BrowserStack username and access key as environment variables.
315
315
 
316
316
  For macOS/Linux:
317
317
  \`\`\`bash
318
- export BROWSERSTACK_USERNAME=${username}
319
- export BROWSERSTACK_ACCESS_KEY=${accessKey}
318
+ export BROWSERSTACK_USERNAME="<your_browserstack_username>"
319
+ export BROWSERSTACK_ACCESS_KEY="<your_browserstack_access_key>"
320
320
  \`\`\`
321
321
 
322
322
  For Windows PowerShell:
323
323
  \`\`\`powershell
324
- $env:BROWSERSTACK_USERNAME=${username}
325
- $env:BROWSERSTACK_ACCESS_KEY=${accessKey}
324
+ $env:BROWSERSTACK_USERNAME="<your_browserstack_username>"
325
+ $env:BROWSERSTACK_ACCESS_KEY="<your_browserstack_access_key>"
326
326
  \`\`\`
327
327
 
328
328
  ---STEP---
@@ -415,7 +415,7 @@ You can now run your tests on BrowserStack using your standard WebdriverIO comma
415
415
  `;
416
416
  return { setup, run };
417
417
  };
418
- export const cypressInstructions = (username, accessKey) => {
418
+ export const cypressInstructions = () => {
419
419
  const setup = `
420
420
  ---STEP---
421
421
 
@@ -445,8 +445,8 @@ Open the generated \`browserstack.json\` file and update it with your BrowserSta
445
445
  \`\`\`json
446
446
  {
447
447
  "auth": {
448
- "username": "${username}",
449
- "access_key": "${accessKey}"
448
+ "username": "<your_browserstack_username>",
449
+ "access_key": "<your_browserstack_access_key>"
450
450
  },
451
451
  "browsers": [
452
452
  {
@@ -490,21 +490,21 @@ npx browserstack-cypress run --sync
490
490
  After the tests complete, you can view the results on your [BrowserStack Automate Dashboard](https://automate.browserstack.com/dashboard/).`;
491
491
  return { setup, run };
492
492
  };
493
- const serenityInstructions = (username, accessKey) => {
493
+ const serenityInstructions = () => {
494
494
  const setup = `
495
495
  ---STEP---
496
496
 
497
497
  Set BrowserStack credentials as environment variables:
498
498
  For macOS/Linux:
499
499
  \`\`\`bash
500
- export BROWSERSTACK_USERNAME=${username}
501
- export BROWSERSTACK_ACCESS_KEY=${accessKey}
500
+ export BROWSERSTACK_USERNAME="<your_browserstack_username>"
501
+ export BROWSERSTACK_ACCESS_KEY="<your_browserstack_access_key>"
502
502
  \`\`\`
503
503
 
504
504
  For Windows Command Prompt:
505
505
  \`\`\`cmd
506
- set BROWSERSTACK_USERNAME=${username}
507
- set BROWSERSTACK_ACCESS_KEY=${accessKey}
506
+ set "BROWSERSTACK_USERNAME=<your_browserstack_username>"
507
+ set "BROWSERSTACK_ACCESS_KEY=<your_browserstack_access_key>"
508
508
  \`\`\`
509
509
 
510
510
  ---STEP---
@@ -528,8 +528,8 @@ webdriver {
528
528
  driver = remote
529
529
  remote.url = "https://hub.browserstack.com/wd/hub"
530
530
  }
531
- browserstack.user="${username}"
532
- browserstack.key="${accessKey}"
531
+ browserstack.user="<your_browserstack_username>"
532
+ browserstack.key="<your_browserstack_access_key>"
533
533
  \`\`\`
534
534
  `;
535
535
  const run = `
@@ -1,12 +1,20 @@
1
- import { getBrowserStackAuth } from "../../../lib/get-auth.js";
2
1
  import { getSDKPrefixCommand } from "./commands.js";
3
2
  import { generateBrowserStackYMLInstructions } from "./configUtils.js";
4
3
  import { getInstructionsForProjectConfiguration } from "../common/instructionUtils.js";
4
+ import { CREDENTIALS_SUBSTITUTION_NOTE } from "../common/credentials.js";
5
5
  import { validateDevices } from "../common/device-validator.js";
6
- export async function runBstackSDKOnly(input, config, isPercyAutomate = false) {
7
- const steps = [];
8
- const authString = getBrowserStackAuth(config);
9
- const [username, accessKey] = authString.split(":");
6
+ export async function runBstackSDKOnly(input,
7
+ // Retained for tool-handler signature stability (callers pass the per-request
8
+ // config); setup instructions no longer embed credentials, so it is unused here.
9
+ config, isPercyAutomate = false) {
10
+ void config;
11
+ const steps = [
12
+ {
13
+ type: "instruction",
14
+ title: "Set your BrowserStack credentials",
15
+ content: CREDENTIALS_SUBSTITUTION_NOTE,
16
+ },
17
+ ];
10
18
  const tupleTargets = input.devices?.map((device) => {
11
19
  const platform = device.platform.toLowerCase();
12
20
  if (platform === "windows" || platform === "macos") {
@@ -32,7 +40,7 @@ export async function runBstackSDKOnly(input, config, isPercyAutomate = false) {
32
40
  // Handle frameworks with unique setup instructions that don't use browserstack.yml
33
41
  if (input.detectedBrowserAutomationFramework === "cypress" ||
34
42
  input.detectedBrowserAutomationFramework === "webdriverio") {
35
- const frameworkInstructions = getInstructionsForProjectConfiguration(input.detectedBrowserAutomationFramework, input.detectedTestingFramework, input.detectedLanguage, username, accessKey);
43
+ const frameworkInstructions = getInstructionsForProjectConfiguration(input.detectedBrowserAutomationFramework, input.detectedTestingFramework, input.detectedLanguage);
36
44
  if (frameworkInstructions) {
37
45
  if (frameworkInstructions.setup) {
38
46
  steps.push({
@@ -56,7 +64,7 @@ export async function runBstackSDKOnly(input, config, isPercyAutomate = false) {
56
64
  };
57
65
  }
58
66
  // Default flow using browserstack.yml
59
- const sdkSetupCommand = getSDKPrefixCommand(input.detectedLanguage, input.detectedTestingFramework, username, accessKey);
67
+ const sdkSetupCommand = getSDKPrefixCommand(input.detectedLanguage, input.detectedTestingFramework);
60
68
  if (sdkSetupCommand) {
61
69
  steps.push({
62
70
  type: "instruction",
@@ -64,7 +72,7 @@ export async function runBstackSDKOnly(input, config, isPercyAutomate = false) {
64
72
  content: sdkSetupCommand,
65
73
  });
66
74
  }
67
- const frameworkInstructions = getInstructionsForProjectConfiguration(input.detectedBrowserAutomationFramework, input.detectedTestingFramework, input.detectedLanguage, username, accessKey);
75
+ const frameworkInstructions = getInstructionsForProjectConfiguration(input.detectedBrowserAutomationFramework, input.detectedTestingFramework, input.detectedLanguage);
68
76
  if (frameworkInstructions) {
69
77
  if (frameworkInstructions.setup) {
70
78
  steps.push({
@@ -78,7 +86,7 @@ export async function runBstackSDKOnly(input, config, isPercyAutomate = false) {
78
86
  validatedEnvironments,
79
87
  enablePercy: false,
80
88
  projectName: input.projectName,
81
- }, config);
89
+ });
82
90
  if (ymlInstructions) {
83
91
  steps.push({
84
92
  type: "instruction",
@@ -0,0 +1,3 @@
1
+ export declare const USERNAME_PLACEHOLDER = "<your_browserstack_username>";
2
+ export declare const ACCESS_KEY_PLACEHOLDER = "<your_browserstack_access_key>";
3
+ export declare const CREDENTIALS_SUBSTITUTION_NOTE: string;
@@ -0,0 +1,11 @@
1
+ // Single source of truth for the credential placeholders emitted in generated
2
+ // SDK setup instructions, so the web (sdk-utils) and App Automate (appium-sdk)
3
+ // trees cannot drift apart. Real credentials are never embedded — see
4
+ // rules/security.md.
5
+ export const USERNAME_PLACEHOLDER = "<your_browserstack_username>";
6
+ export const ACCESS_KEY_PLACEHOLDER = "<your_browserstack_access_key>";
7
+ // Tells the reader (often a coding agent that runs steps verbatim) to swap the
8
+ // placeholders for real values, so they are not baked into browserstack.yml.
9
+ export const CREDENTIALS_SUBSTITUTION_NOTE = `Replace ${USERNAME_PLACEHOLDER} and ${ACCESS_KEY_PLACEHOLDER} in the steps below ` +
10
+ `with your BrowserStack credentials from https://www.browserstack.com/accounts/profile/details ` +
11
+ `(or export them as BROWSERSTACK_USERNAME / BROWSERSTACK_ACCESS_KEY). Do not commit real credentials.`;
@@ -2,7 +2,7 @@
2
2
  * Core instruction configuration utilities for runTestsOnBrowserStack tool.
3
3
  */
4
4
  import { SDKSupportedLanguage, SDKSupportedBrowserAutomationFramework, SDKSupportedTestingFramework } from "./types.js";
5
- export declare const getInstructionsForProjectConfiguration: (detectedBrowserAutomationFramework: SDKSupportedBrowserAutomationFramework, detectedTestingFramework: SDKSupportedTestingFramework, detectedLanguage: SDKSupportedLanguage, username: string, accessKey: string) => {
5
+ export declare const getInstructionsForProjectConfiguration: (detectedBrowserAutomationFramework: SDKSupportedBrowserAutomationFramework, detectedTestingFramework: SDKSupportedTestingFramework, detectedLanguage: SDKSupportedLanguage) => {
6
6
  setup: string;
7
7
  run: string;
8
8
  };
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import { SUPPORTED_CONFIGURATIONS } from "../bstack/frameworks.js";
5
5
  const errorMessageSuffix = "Please open an issue at our Github repo: https://github.com/browserstack/browserstack-mcp-server/issues to request support for your project configuration";
6
- export const getInstructionsForProjectConfiguration = (detectedBrowserAutomationFramework, detectedTestingFramework, detectedLanguage, username, accessKey) => {
6
+ export const getInstructionsForProjectConfiguration = (detectedBrowserAutomationFramework, detectedTestingFramework, detectedLanguage) => {
7
7
  const configuration = SUPPORTED_CONFIGURATIONS[detectedLanguage];
8
8
  if (!configuration) {
9
9
  throw new Error(`BrowserStack MCP Server currently does not support ${detectedLanguage}, ${errorMessageSuffix}`);
@@ -16,5 +16,5 @@ export const getInstructionsForProjectConfiguration = (detectedBrowserAutomation
16
16
  }
17
17
  const instructionFunction = configuration[detectedBrowserAutomationFramework][detectedTestingFramework]
18
18
  .instructions;
19
- return instructionFunction(username, accessKey);
19
+ return instructionFunction();
20
20
  };
@@ -43,7 +43,7 @@ export declare const SDKSupportedLanguages: SDKSupportedLanguageEnum[];
43
43
  export type SDKSupportedTestingFramework = keyof typeof SDKSupportedTestingFrameworkEnum;
44
44
  export declare const SDKSupportedTestingFrameworks: SDKSupportedTestingFrameworkEnum[];
45
45
  export type ConfigMapping = Partial<Record<SDKSupportedLanguageEnum, Partial<Record<SDKSupportedBrowserAutomationFrameworkEnum, Partial<Record<SDKSupportedTestingFrameworkEnum, {
46
- instructions: (username: string, accessKey: string) => {
46
+ instructions: () => {
47
47
  setup: string;
48
48
  run: string;
49
49
  };
@@ -55,7 +55,7 @@ export async function setUpPercyHandler(rawInput, config) {
55
55
  const percyWithBrowserstackSDKResult = runPercyWithBrowserstackSDK({
56
56
  ...percyInput,
57
57
  devices: [],
58
- }, config);
58
+ });
59
59
  const hasPercySDKError = percyWithBrowserstackSDKResult.steps &&
60
60
  percyWithBrowserstackSDKResult.steps.some((step) => step.isError);
61
61
  if (!hasPercySDKError) {
@@ -1,4 +1,3 @@
1
1
  import { RunTestsInstructionResult } from "../common/types.js";
2
2
  import { RunTestsOnBrowserStackInput } from "../common/schema.js";
3
- import { BrowserStackConfig } from "../../../lib/types.js";
4
- export declare function runPercyWithBrowserstackSDK(input: RunTestsOnBrowserStackInput, config: BrowserStackConfig): RunTestsInstructionResult;
3
+ export declare function runPercyWithBrowserstackSDK(input: RunTestsOnBrowserStackInput): RunTestsInstructionResult;
@@ -1,12 +1,16 @@
1
- import { getBrowserStackAuth } from "../../../lib/get-auth.js";
2
1
  import { getSDKPrefixCommand } from "../bstack/commands.js";
3
2
  import { generateBrowserStackYMLInstructions } from "../bstack/configUtils.js";
4
3
  import { getInstructionsForProjectConfiguration } from "../common/instructionUtils.js";
4
+ import { CREDENTIALS_SUBSTITUTION_NOTE } from "../common/credentials.js";
5
5
  import { formatPercyInstructions, getPercyInstructions, } from "./instructions.js";
6
- export function runPercyWithBrowserstackSDK(input, config) {
7
- const steps = [];
8
- const authString = getBrowserStackAuth(config);
9
- const [username, accessKey] = authString.split(":");
6
+ export function runPercyWithBrowserstackSDK(input) {
7
+ const steps = [
8
+ {
9
+ type: "instruction",
10
+ title: "Set your BrowserStack credentials",
11
+ content: CREDENTIALS_SUBSTITUTION_NOTE,
12
+ },
13
+ ];
10
14
  // Check if Percy is supported for this configuration
11
15
  const percyResult = getPercyInstructions(input.detectedLanguage, input.detectedBrowserAutomationFramework, input.detectedTestingFramework);
12
16
  if (!percyResult) {
@@ -28,7 +32,7 @@ export function runPercyWithBrowserstackSDK(input, config) {
28
32
  // Handle frameworks with unique setup instructions that don't use browserstack.yml
29
33
  if (input.detectedBrowserAutomationFramework === "cypress" ||
30
34
  input.detectedBrowserAutomationFramework === "webdriverio") {
31
- const frameworkInstructions = getInstructionsForProjectConfiguration(input.detectedBrowserAutomationFramework, input.detectedTestingFramework, input.detectedLanguage, username, accessKey);
35
+ const frameworkInstructions = getInstructionsForProjectConfiguration(input.detectedBrowserAutomationFramework, input.detectedTestingFramework, input.detectedLanguage);
32
36
  if (frameworkInstructions && frameworkInstructions.setup) {
33
37
  steps.push({
34
38
  type: "instruction",
@@ -55,7 +59,7 @@ export function runPercyWithBrowserstackSDK(input, config) {
55
59
  };
56
60
  }
57
61
  // Default flow using browserstack.yml with Percy
58
- const sdkSetupCommand = getSDKPrefixCommand(input.detectedLanguage, input.detectedTestingFramework, username, accessKey);
62
+ const sdkSetupCommand = getSDKPrefixCommand(input.detectedLanguage, input.detectedTestingFramework);
59
63
  if (sdkSetupCommand) {
60
64
  steps.push({
61
65
  type: "instruction",
@@ -67,7 +71,7 @@ export function runPercyWithBrowserstackSDK(input, config) {
67
71
  platforms: input.devices?.map((t) => t.join(" ")) || [],
68
72
  enablePercy: true,
69
73
  projectName: input.projectName,
70
- }, config);
74
+ });
71
75
  if (ymlInstructions) {
72
76
  steps.push({
73
77
  type: "instruction",
@@ -75,7 +79,7 @@ export function runPercyWithBrowserstackSDK(input, config) {
75
79
  content: ymlInstructions,
76
80
  });
77
81
  }
78
- const frameworkInstructions = getInstructionsForProjectConfiguration(input.detectedBrowserAutomationFramework, input.detectedTestingFramework, input.detectedLanguage, username, accessKey);
82
+ const frameworkInstructions = getInstructionsForProjectConfiguration(input.detectedBrowserAutomationFramework, input.detectedTestingFramework, input.detectedLanguage);
79
83
  if (frameworkInstructions && frameworkInstructions.setup) {
80
84
  steps.push({
81
85
  type: "instruction",
@@ -3,6 +3,7 @@ import { z } from "zod";
3
3
  import { formatAxiosError } from "../../lib/error.js";
4
4
  import { fetchFormFields, normalizeDefaultFields as normalizeDefaultFieldsFromForm, projectIdentifierToId, } from "./TCG-utils/api.js";
5
5
  import { getTMBaseURL } from "../../lib/tm-base-url.js";
6
+ import { wrapRichText, wrapTestCaseSteps } from "./rich-text.js";
6
7
  import logger from "../../logger.js";
7
8
  // Scalar value, or an array of values for multi-select custom fields.
8
9
  export const customFieldValueSchema = z.union([
@@ -189,6 +190,13 @@ async function toV1CustomFields(customFields, numericProjectId, config) {
189
190
  export async function createTestCase(params, config) {
190
191
  const testCaseParams = { ...params };
191
192
  testCaseParams.tags = Array.from(new Set([...(testCaseParams.tags ?? []), "MCP Generated"]));
193
+ testCaseParams.test_case_steps = wrapTestCaseSteps(testCaseParams.test_case_steps);
194
+ if (testCaseParams.preconditions !== undefined) {
195
+ testCaseParams.preconditions = wrapRichText(testCaseParams.preconditions);
196
+ }
197
+ if (testCaseParams.description !== undefined) {
198
+ testCaseParams.description = wrapRichText(testCaseParams.description);
199
+ }
192
200
  if (testCaseParams.priority !== undefined ||
193
201
  testCaseParams.case_type !== undefined) {
194
202
  const normalized = await normalizeDefaultFields(params.project_identifier, {
@@ -0,0 +1,5 @@
1
+ export declare function wrapRichText(text: string): string;
2
+ export declare function wrapTestCaseSteps<T extends {
3
+ step: string;
4
+ result: string;
5
+ }>(steps: T[]): T[];
@@ -0,0 +1,22 @@
1
+ // TM renders these fields as rich text only when the value is HTML;
2
+ const TM_ALLOWED_TAG = /^\s*<(div|img|b|em|i|strong|u|span|abbr|br|cite|code|dd|dfn|dl|dt|kbd|li|mark|ol|p|pre|q|s|samp|small|strike|sub|sup|time|ul|var|table|td|th|thead|tbody|tr|col|colgroup|a)[\s/>]/i;
3
+ const HAS_ENCODABLE_CHARS = /[<>&]/;
4
+ function escapeHtml(text) {
5
+ return text
6
+ .replace(/&/g, "&amp;")
7
+ .replace(/</g, "&lt;")
8
+ .replace(/>/g, "&gt;");
9
+ }
10
+ export function wrapRichText(text) {
11
+ if (TM_ALLOWED_TAG.test(text) || !HAS_ENCODABLE_CHARS.test(text)) {
12
+ return text;
13
+ }
14
+ return `<p>${escapeHtml(text)}</p>`;
15
+ }
16
+ export function wrapTestCaseSteps(steps) {
17
+ return steps.map((s) => ({
18
+ ...s,
19
+ step: wrapRichText(s.step),
20
+ result: wrapRichText(s.result),
21
+ }));
22
+ }
@@ -4,6 +4,7 @@ import { formatAxiosError } from "../../lib/error.js";
4
4
  import { fetchFormFields, normalizeDefaultFields as normalizeDefaultFieldsFromForm, projectIdentifierToId, } from "./TCG-utils/api.js";
5
5
  import { getTMBaseURL } from "../../lib/tm-base-url.js";
6
6
  import { getBrowserStackAuth } from "../../lib/get-auth.js";
7
+ import { wrapRichText, wrapTestCaseSteps } from "./rich-text.js";
7
8
  import logger from "../../logger.js";
8
9
  export const UpdateTestCaseSchema = z.object({
9
10
  project_identifier: z
@@ -107,11 +108,11 @@ export async function updateTestCase(params, config) {
107
108
  if (params.name !== undefined)
108
109
  testCaseBody.name = params.name;
109
110
  if (params.description !== undefined)
110
- testCaseBody.description = params.description;
111
+ testCaseBody.description = wrapRichText(params.description);
111
112
  if (params.preconditions !== undefined)
112
- testCaseBody.preconditions = params.preconditions;
113
+ testCaseBody.preconditions = wrapRichText(params.preconditions);
113
114
  if (params.test_case_steps !== undefined)
114
- testCaseBody.test_case_steps = params.test_case_steps;
115
+ testCaseBody.test_case_steps = wrapTestCaseSteps(params.test_case_steps);
115
116
  if (params.owner !== undefined)
116
117
  testCaseBody.owner = params.owner;
117
118
  if (params.status !== undefined)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@browserstack/mcp-server",
3
- "version": "1.2.31",
3
+ "version": "1.2.33-beta.1",
4
4
  "description": "BrowserStack's Official MCP Server",
5
5
  "mcpName": "io.github.browserstack/mcp-server",
6
6
  "main": "dist/index.js",