Skip to content

Refactoring SDK Tool #101

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
b589b4e
Refactoring SDK Tool
tech-sushant Jul 22, 2025
7f0bd97
add projectName parameter to BrowserStack YML instructions
tech-sushant Jul 23, 2025
d2f7a6d
Percy changes
tech-sushant Jul 28, 2025
395153c
Add framework compatibility checks for Percy integration types
tech-sushant Jul 28, 2025
ccf16a9
Refactor Percy handler functions to remove unsupported configuration …
tech-sushant Jul 28, 2025
c2e6d82
Update tool descriptions and registration names for BrowserStack and …
tech-sushant Jul 28, 2025
6bc96cd
Update Percy integration type and adjust related documentation for Au…
tech-sushant Jul 30, 2025
c67e857
Refactor BrowserStack and Percy integration tools for improved setup …
tech-sushant Jul 30, 2025
0d5b48b
Merge branch 'main' into bstack-sdk
tech-sushant Jul 30, 2025
38fd222
Update command for running Percy Automate with BrowserStack and Pytest
tech-sushant Jul 30, 2025
0c84983
Merge branch 'bstack-sdk' of https://github.com/tech-sushant/mcp-serv…
tech-sushant Jul 30, 2025
7132f0a
Add Percy tools integration and support checks for BrowserStack
tech-sushant Jul 30, 2025
f1456b8
Enhance BrowserStack SDK integration
tech-sushant Jul 30, 2025
c7c5c56
Refactor Percy token handling
tech-sushant Jul 30, 2025
ef7a337
linting
tech-sushant Jul 30, 2025
c5b07c5
Remove config logging from bootstrap failure message and delete unuse…
tech-sushant Jul 31, 2025
970d3ec
Remove integrationType from SetUpPercyParamsShape and update support …
tech-sushant Jul 31, 2025
8e29b42
Update SETUP_PERCY_DESCRIPTION for clarity on tool usage and integration
tech-sushant Jul 31, 2025
6185e9e
Refactor BrowserStack and Percy integration descriptions for clarity …
tech-sushant Aug 1, 2025
c80f25c
Percy changes
tech-sushant Aug 1, 2025
5483db3
Refactor Percy and BrowserStack integration
tech-sushant Aug 1, 2025
da46709
Enhance Percy integration documentation and support for additional fr…
tech-sushant Aug 3, 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
1 change: 0 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,5 @@ process.on("exit", () => {
logger.flush();
});


export { setLogger } from "./logger.js";
export { BrowserStackMcpServer } from "./server-factory.js";
4 changes: 3 additions & 1 deletion src/server-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const require = createRequire(import.meta.url);
const packageJson = require("../package.json");
import logger from "./logger.js";
import addSDKTools from "./tools/bstack-sdk.js";
import addPercyTools from "./tools/percy-sdk.js";
import addBrowserLiveTools from "./tools/live.js";
import addAccessibilityTools from "./tools/accessibility.js";
import addTestManagementTools from "./tools/testmanagement.js";
Expand Down Expand Up @@ -48,6 +49,7 @@ export class BrowserStackMcpServer {
const toolAdders = [
addAccessibilityTools,
addSDKTools,
addPercyTools,
addAppLiveTools,
addBrowserLiveTools,
addTestManagementTools,
Expand Down Expand Up @@ -80,7 +82,7 @@ export class BrowserStackMcpServer {
public getTools(): Record<string, RegisteredTool> {
return this.tools;
}

public getTool(name: string): RegisteredTool | undefined {
return this.tools[name];
}
Expand Down
252 changes: 12 additions & 240 deletions src/tools/bstack-sdk.ts
Original file line number Diff line number Diff line change
@@ -1,254 +1,26 @@
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";
import { trackMCP } from "../lib/instrumentation.js";
import { getSDKPrefixCommand } from "./sdk-utils/commands.js";

import {
SDKSupportedBrowserAutomationFramework,
SDKSupportedLanguage,
SDKSupportedTestingFramework,
SDKSupportedLanguageEnum,
SDKSupportedBrowserAutomationFrameworkEnum,
SDKSupportedTestingFrameworkEnum,
} from "./sdk-utils/types.js";

import {
generateBrowserStackYMLInstructions,
getInstructionsForProjectConfiguration,
formatInstructionsWithNumbers,
} from "./sdk-utils/instructions.js";

import {
formatPercyInstructions,
getPercyInstructions,
} from "./sdk-utils/percy/instructions.js";
import { getBrowserStackAuth } from "../lib/get-auth.js";
import { BrowserStackConfig } from "../lib/types.js";
import { RunTestsOnBrowserStackParamsShape } from "./sdk-utils/common/schema.js";
import { runTestsOnBrowserStackHandler } from "./sdk-utils/handler.js";

/**
* BrowserStack SDK hooks into your test framework to seamlessly run tests on BrowserStack.
* This tool gives instructions to setup a browserstack.yml file in the project root and installs the necessary dependencies.
*/
export async function bootstrapProjectWithSDK({
detectedBrowserAutomationFramework,
detectedTestingFramework,
detectedLanguage,
desiredPlatforms,
enablePercy,
config,
}: {
detectedBrowserAutomationFramework: SDKSupportedBrowserAutomationFramework;
detectedTestingFramework: SDKSupportedTestingFramework;
detectedLanguage: SDKSupportedLanguage;
desiredPlatforms: string[];
enablePercy: boolean;
config: BrowserStackConfig;
}): Promise<CallToolResult> {
// Get credentials from config
const authString = getBrowserStackAuth(config);
const [username, accessKey] = authString.split(":");

// Handle frameworks with unique setup instructions that don't use browserstack.yml
if (
detectedBrowserAutomationFramework === "cypress" ||
detectedTestingFramework === "webdriverio"
) {
let combinedInstructions = getInstructionsForProjectConfiguration(
detectedBrowserAutomationFramework,
detectedTestingFramework,
detectedLanguage,
username,
accessKey,
);

if (enablePercy) {
const percyInstructions = getPercyInstructions(
detectedLanguage,
detectedBrowserAutomationFramework,
detectedTestingFramework,
);
const RUN_ON_BROWSERSTACK_DESCRIPTION =
"Set up and run automated web-based tests on BrowserStack using the BrowserStack SDK. Use this tool for functional or integration test setup on BrowserStack only. For any visual testing or Percy integration, use the dedicated Percy setup tool. Example prompts: run this test on browserstack; set up this project for browserstack.";

if (percyInstructions) {
combinedInstructions +=
"\n\n" + 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.`,
);
}
}

// Apply consistent formatting for all configurations
return formatFinalInstructions(combinedInstructions);
}

// Handle default flow using browserstack.yml
const sdkSetupCommand = getSDKPrefixCommand(
detectedLanguage,
detectedTestingFramework,
username,
accessKey,
);

const ymlInstructions = generateBrowserStackYMLInstructions(
desiredPlatforms,
enablePercy,
);

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

let combinedInstructions = "";

// Step 1: Add SDK setup command
if (sdkSetupCommand) {
combinedInstructions += sdkSetupCommand;
}

// Step 2: Add browserstack.yml setup
if (ymlInstructions) {
combinedInstructions += "\n\n---STEP---\n" + ymlInstructions;
}

// Step 3: Add language/framework-specific setup
if (instructionsForProjectConfiguration) {
combinedInstructions += "\n\n" + instructionsForProjectConfiguration;
}

// Step 4: Add Percy setup if applicable
if (enablePercy) {
const percyInstructions = getPercyInstructions(
detectedLanguage,
detectedBrowserAutomationFramework,
detectedTestingFramework,
);

if (percyInstructions) {
combinedInstructions +=
"\n\n" + 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.`,
);
}
}

// Apply consistent formatting for all configurations
return formatFinalInstructions(combinedInstructions);
}

// Helper function to apply consistent formatting to all instruction types
function formatFinalInstructions(combinedInstructions: string): CallToolResult {
const fullInstructions = `⚠️ IMPORTANT: DO NOT SKIP ANY STEP
All the setup steps described in this file MUST be executed regardless of any existing configuration or setup.
This ensures proper BrowserStack SDK setup.

${formatInstructionsWithNumbers(combinedInstructions)}`;

return {
content: [
{
type: "text",
text: fullInstructions,
isError: false,
},
],
};
}

export default function addSDKTools(
export function registerRunBrowserStackTestsTool(
server: McpServer,
config: BrowserStackConfig,
) {
const tools: Record<string, any> = {};

tools.runTestsOnBrowserStack = server.tool(
"runTestsOnBrowserStack",
"Use this tool to get instructions for running tests on BrowserStack and BrowserStack Percy. It sets up the BrowserStack SDK and runs your test cases on BrowserStack.",
{
detectedBrowserAutomationFramework: z
.nativeEnum(SDKSupportedBrowserAutomationFrameworkEnum)
.describe(
"The automation framework configured in the project. Example: 'playwright', 'selenium'",
),

detectedTestingFramework: z
.nativeEnum(SDKSupportedTestingFrameworkEnum)
.describe(
"The testing framework used in the project. Be precise with framework selection Example: 'webdriverio', 'jest', 'pytest', 'junit4', 'junit5', 'mocha'",
),

detectedLanguage: z
.nativeEnum(SDKSupportedLanguageEnum)
.describe(
"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.",
),
},

tools.setupBrowserStackAutomateTests = server.tool(
"setupBrowserStackAutomateTests",
RUN_ON_BROWSERSTACK_DESCRIPTION,
RunTestsOnBrowserStackParamsShape,
async (args) => {
try {
trackMCP(
"runTestsOnBrowserStack",
server.server.getClientVersion()!,
undefined,
config,
);

return await bootstrapProjectWithSDK({
detectedBrowserAutomationFramework:
args.detectedBrowserAutomationFramework as SDKSupportedBrowserAutomationFramework,

detectedTestingFramework:
args.detectedTestingFramework as SDKSupportedTestingFramework,

detectedLanguage: args.detectedLanguage as SDKSupportedLanguage,

desiredPlatforms: args.desiredPlatforms,
enablePercy: args.enablePercy,
config,
});
} catch (error) {
trackMCP(
"runTestsOnBrowserStack",
server.server.getClientVersion()!,
error,
config,
);

return {
content: [
{
type: "text",
text: `Failed to bootstrap project with BrowserStack SDK. Error: ${error}. Please open an issue on GitHub if the problem persists`,
isError: true,
},
],
isError: true,
};
}
return runTestsOnBrowserStackHandler(args, config);
},
);

return tools;
}

export default registerRunBrowserStackTestsTool;
32 changes: 32 additions & 0 deletions src/tools/percy-sdk.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { BrowserStackConfig } from "../lib/types.js";
import { SetUpPercyParamsShape } from "./sdk-utils/common/schema.js";
import { setUpPercyHandler } from "./sdk-utils/handler.js";

/**
* Tool description for standalone Percy visual testing
*/
const SETUP_PERCY_DESCRIPTION =
"Set up Percy visual testing for your project. This supports both Percy Web Standalone and Percy Automate.";

/**
* Registers the standalone Percy setup tool with the MCP server.
* Focuses on Percy Web and Percy Automate without BrowserStack integration.
*/
export function registerPercySetupTool(
server: McpServer,
config: BrowserStackConfig,
) {
const tools: Record<string, any> = {};
tools.setupPercyVisualTesting = server.tool(
"setupPercyVisualTesting",
SETUP_PERCY_DESCRIPTION,
SetUpPercyParamsShape,
async (args) => {
return setUpPercyHandler(args, config);
},
);
return tools;
}

export default registerPercySetupTool;
Loading