Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
fae52fa
Adding SDK
tech-sushant Jun 16, 2025
cc9f890
feat: enhance BrowserStack SDK with Percy support and framework-speci…
ruturaj-browserstack Jun 17, 2025
da86163
feat: enhance SDK support
tech-sushant Jun 17, 2025
3b6d7d3
Update bstack-sdk.ts
tech-sushant Jun 17, 2025
d3f93c9
feat: update getSDKPrefixCommand to include testing framework for Jav…
ruturaj-browserstack Jun 18, 2025
234984a
add C# Playwright NUnit instructions
tech-sushant Jun 19, 2025
57954d3
Merge branch 'cont-regression' of https://github.com/tech-sushant/mcp…
tech-sushant Jun 19, 2025
778372b
Adding the setups
tech-sushant Jun 19, 2025
b92deb6
feat: enhance SDK setup instructions for Java and add Cucumber suppor…
ruturaj-browserstack Jun 19, 2025
6e6eef6
feat: update C# instructions for Apple Silicon and add MSTest support
tech-sushant Jun 19, 2025
d3d5474
++instructions
tech-sushant Jun 19, 2025
4292ac2
feat: add Percy instructions to bootstrapProjectWithSDK for enhanced …
ruturaj-browserstack Jun 20, 2025
669f086
Merge pull request #5 from ruturaj-browserstack/main
ruturaj-browserstack Jun 20, 2025
0c34386
Merge branch 'SDK_PERCY_1' into cont-regression
tech-sushant Jun 20, 2025
93e3f4e
Merge pull request #6 from tech-sushant/cont-regression
ruturaj-browserstack Jun 20, 2025
dad3ac8
feat: enhance Java SDK setup instructions and update testing framewor…
ruturaj-browserstack Jun 20, 2025
b745d0b
feat: add error handling for Percy support and include C# Selenium in…
ruturaj-browserstack Jun 20, 2025
f7259ed
chore: remove commented instruction placeholder for nodejs+playwright…
ruturaj-browserstack Jun 20, 2025
ac3dd47
chore: remove cucumber instructions from PERCY_INSTRUCTIONS
ruturaj-browserstack Jun 20, 2025
6d9fae1
++ enhancing instructions
tech-sushant Jun 20, 2025
3e1345e
fix: correct method name from percy.snapshot to percy.screenshot in N…
ruturaj-browserstack Jun 20, 2025
b387332
fix: update BrowserStack environment variable instructions for consis…
ruturaj-browserstack Jun 20, 2025
232768e
Merge pull request #6 from ruturaj-browserstack/SDK_PERCY_1
tech-sushant Jun 20, 2025
22c242d
Merge pull request #5 from tech-sushant/feature-cont
tech-sushant Jun 20, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 84 additions & 8 deletions src/tools/bstack-sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,20 @@ import {
SDKSupportedBrowserAutomationFramework,
SDKSupportedLanguage,
SDKSupportedTestingFramework,
SDKSupportedLanguageEnum,
SDKSupportedBrowserAutomationFrameworkEnum,
SDKSupportedTestingFrameworkEnum,
} from "./sdk-utils/types.js";
import {
generateBrowserStackYMLInstructions,
getInstructionsForProjectConfiguration,
} from "./sdk-utils/instructions.js";
import { trackMCP } from "../lib/instrumentation.js";
import {
formatPercyInstructions,
getPercyInstructions,
} from "./sdk-utils/percy/instructions.js";
import { getSDKPrefixCommand } from "./sdk-utils/commands.js";

/**
* BrowserStack SDK hooks into your test framework to seamlessly run tests on BrowserStack.
Expand All @@ -21,25 +29,85 @@ export async function bootstrapProjectWithSDK({
detectedTestingFramework,
detectedLanguage,
desiredPlatforms,
enablePercy,
}: {
detectedBrowserAutomationFramework: SDKSupportedBrowserAutomationFramework;
detectedTestingFramework: SDKSupportedTestingFramework;
detectedLanguage: SDKSupportedLanguage;
desiredPlatforms: string[];
enablePercy: boolean;
}): Promise<CallToolResult> {
const instructions = generateBrowserStackYMLInstructions(desiredPlatforms);
// Handle frameworks with unique setup instructions that don't use browserstack.yml
if (
detectedBrowserAutomationFramework === "cypress" ||
detectedTestingFramework === "webdriverio"
) {
let instructions = getInstructionsForProjectConfiguration(
detectedBrowserAutomationFramework,
detectedTestingFramework,
detectedLanguage,
);
if (enablePercy) {
const percyInstructions = getPercyInstructions(
detectedLanguage,
detectedBrowserAutomationFramework,
detectedTestingFramework,
);
if (percyInstructions) {
instructions += formatPercyInstructions(percyInstructions);
} else {
throw new Error(
`Percy is currently not supported through MCP for ${detectedLanguage} with ${detectedTestingFramework}. If you want to run the test cases without Percy, disable Percy and run it again.`,
);
}
}
return {
content: [{ type: "text", text: instructions, isError: false }],
};
}

let fullInstructions = "";
// Add language-dependent prefix command
fullInstructions += getSDKPrefixCommand(
detectedLanguage,
detectedTestingFramework,
);

const ymlInstructions = generateBrowserStackYMLInstructions(
desiredPlatforms,
enablePercy,
);
fullInstructions += `${ymlInstructions}`;

const instructionsForProjectConfiguration =
getInstructionsForProjectConfiguration(
detectedBrowserAutomationFramework,
detectedTestingFramework,
detectedLanguage,
);

if (enablePercy) {
const percyInstructions = getPercyInstructions(
detectedLanguage,
detectedBrowserAutomationFramework,
detectedTestingFramework,
);
if (percyInstructions) {
fullInstructions += formatPercyInstructions(percyInstructions);
} else {
throw new Error(
`Percy is currently not supported through MCP for ${detectedLanguage} with ${detectedTestingFramework}. If you want to run the test cases without Percy, disable Percy and run it again.`,
);
}
}

fullInstructions += `\n\nAfter setting up the files above, follow these final steps:\n${instructionsForProjectConfiguration}`;

return {
content: [
{
type: "text",
text: `${instructions}\n\n After creating the browserstack.yml file above, do the following: ${instructionsForProjectConfiguration}`,
text: fullInstructions,
isError: false,
},
],
Expand All @@ -49,28 +117,35 @@ export async function bootstrapProjectWithSDK({
export default function addSDKTools(server: McpServer) {
server.tool(
"runTestsOnBrowserStack",
"Use this tool to get instructions for running tests on BrowserStack.",
"Use this tool to get instructions for running tests on BrowserStack and browserstack percy",
{
detectedBrowserAutomationFramework: z
.string()
.nativeEnum(SDKSupportedBrowserAutomationFrameworkEnum)
.describe(
"The automation framework configured in the project. Example: 'playwright', 'selenium'",
),
detectedTestingFramework: z
.string()
.nativeEnum(SDKSupportedTestingFrameworkEnum)
.describe(
"The testing framework used in the project. Example: 'jest', 'pytest'",
"The testing framework used in the project. Be precise with framework selection Example: 'webdriverio', 'jest', 'pytest', 'junit4', 'junit5', 'mocha'",
),
detectedLanguage: z
.string()
.nativeEnum(SDKSupportedLanguageEnum)
.describe(
"The programming language used in the project. Example: 'nodejs', 'python'",
"The programming language used in the project. Example: 'nodejs', 'python', 'java', 'csharp'",
),
desiredPlatforms: z
.array(z.enum(["windows", "macos", "android", "ios"]))
.describe(
"The platforms the user wants to test on. Always ask this to the user, do not try to infer this.",
),
enablePercy: z
.boolean()
.optional()
.default(false)
.describe(
"Set to true if the user wants to enable Percy for visual testing. Defaults to false.",
),
},
async (args) => {
try {
Expand All @@ -83,6 +158,7 @@ export default function addSDKTools(server: McpServer) {
args.detectedTestingFramework as SDKSupportedTestingFramework,
detectedLanguage: args.detectedLanguage as SDKSupportedLanguage,
desiredPlatforms: args.desiredPlatforms,
enablePercy: args.enablePercy,
});
} catch (error) {
trackMCP(
Expand Down
64 changes: 64 additions & 0 deletions src/tools/sdk-utils/commands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Utility to get the language-dependent prefix command for BrowserStack SDK setup
import { SDKSupportedLanguage } from "./types.js";

// Framework mapping for Java Maven archetype generation
const JAVA_FRAMEWORK_MAP: Record<string, string> = {
testng: "testng",
junit5: "junit5",
junit4: "junit4",
cucumber: "cucumber-testng",
};

// Common Gradle setup instructions (platform-independent)
const GRADLE_SETUP_INSTRUCTIONS = `
**For Gradle setup:**
1. Add browserstack-java-sdk to dependencies:
compileOnly 'com.browserstack:browserstack-java-sdk:latest.release'

2. Add browserstackSDK path variable:
def browserstackSDKArtifact = configurations.compileClasspath.resolvedConfiguration.resolvedArtifacts.find { it.name == 'browserstack-java-sdk' }

3. Add javaagent to gradle tasks:
jvmArgs "-javaagent:\${browserstackSDKArtifact.file}"
`;

export function getSDKPrefixCommand(
language: SDKSupportedLanguage,
framework: string,
): string {
switch (language) {
case "nodejs":
return `Install BrowserStack Node SDK\nusing command | npm i -D browserstack-node-sdk@latest\n| and then run following command to setup browserstack sdk:\n npx setup --username ${process.env.BROWSERSTACK_USERNAME} --key ${process.env.BROWSERSTACK_ACCESS_KEY}\n\n. This will create browserstack.yml file in the project root. Edit the file to add your desired platforms and browsers. If the file is not created :\n`;

case "java": {
const mavenFramework = getJavaFrameworkForMaven(framework);
const isWindows = process.platform === "win32";

const mavenCommand = isWindows
? `mvn archetype:generate -B -DarchetypeGroupId="com.browserstack" -DarchetypeArtifactId="browserstack-sdk-archetype-integrate" -DarchetypeVersion="1.0" -DgroupId="com.browserstack" -DartifactId="browserstack-sdk-archetype-integrate" -Dversion="1.0" -DBROWSERSTACK_USERNAME="${process.env.BROWSERSTACK_USERNAME}" -DBROWSERSTACK_ACCESS_KEY="${process.env.BROWSERSTACK_ACCESS_KEY}" -DBROWSERSTACK_FRAMEWORK="${mavenFramework}"`
: `mvn archetype:generate -B -DarchetypeGroupId=com.browserstack \\
-DarchetypeArtifactId=browserstack-sdk-archetype-integrate -DarchetypeVersion=1.0 \\
-DgroupId=com.browserstack -DartifactId=browserstack-sdk-archetype-integrate -Dversion=1.0 \\
-DBROWSERSTACK_USERNAME="${process.env.BROWSERSTACK_USERNAME}" \\
-DBROWSERSTACK_ACCESS_KEY="${process.env.BROWSERSTACK_ACCESS_KEY}" \\
-DBROWSERSTACK_FRAMEWORK="${mavenFramework}"`;

const platformLabel = isWindows ? "Windows" : "macOS/Linux";

return `Install BrowserStack Java SDK

**Maven command for ${framework} (${platformLabel}):**
Run the command, it is required to generate the browserstack-sdk-archetype-integrate project:
${mavenCommand}
${GRADLE_SETUP_INSTRUCTIONS}`;
}

// Add more languages as needed
default:
return "";
}
}

export function getJavaFrameworkForMaven(framework: string): string {
return JAVA_FRAMEWORK_MAP[framework] || framework;
}
Loading