Skip to content

Feat : Added Tools in sdk context #103

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

Merged
merged 4 commits into from
Jul 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 5 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const require = createRequire(import.meta.url);
const packageJson = require("../package.json");
import "dotenv/config";
import logger from "./logger.js";
import { createMcpServer } from "./server-factory.js";
import { BrowserStackMcpServer } from "./server-factory.js";

async function main() {
logger.info(
Expand All @@ -33,12 +33,12 @@ async function main() {

const transport = new StdioServerTransport();

const server = createMcpServer({
const mcpServer = new BrowserStackMcpServer({
"browserstack-username": username,
"browserstack-access-key": accessKey,
});

await server.connect(transport);
await mcpServer.getInstance().connect(transport);
}

main().catch(console.error);
Expand All @@ -48,5 +48,6 @@ process.on("exit", () => {
logger.flush();
});

export { createMcpServer } from "./server-factory.js";

export { setLogger } from "./logger.js";
export { BrowserStackMcpServer } from "./server-factory.js";
91 changes: 66 additions & 25 deletions src/server-factory.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import {
McpServer,
RegisteredTool,
} from "@modelcontextprotocol/sdk/server/mcp.js";
import { createRequire } from "module";
const require = createRequire(import.meta.url);
const packageJson = require("../package.json");
Expand All @@ -15,32 +18,70 @@ import addAppLiveTools from "./tools/applive.js";
import { setupOnInitialized } from "./oninitialized.js";
import { BrowserStackConfig } from "./lib/types.js";

function registerTools(server: McpServer, config: BrowserStackConfig) {
addAccessibilityTools(server, config);
addSDKTools(server, config);
addAppLiveTools(server, config);
addBrowserLiveTools(server, config);
addTestManagementTools(server, config);
addAppAutomationTools(server, config);
addFailureLogsTools(server, config);
addAutomateTools(server, config);
addSelfHealTools(server, config);
}
/**
* Wrapper class for BrowserStack MCP Server
* Stores a map of registered tools by name
*/
export class BrowserStackMcpServer {
public server: McpServer;
public tools: Record<string, RegisteredTool> = {};

constructor(private config: BrowserStackConfig) {
logger.info(
"Creating BrowserStack MCP Server, version %s",
packageJson.version,
);

this.server = new McpServer({
name: "BrowserStack MCP Server",
version: packageJson.version,
});

setupOnInitialized(this.server, this.config);
this.registerTools();
}

export function createMcpServer(config: BrowserStackConfig): McpServer {
logger.info(
"Creating BrowserStack MCP Server, version %s",
packageJson.version,
);
/**
* Calls each tool-adder function and collects their returned tools
*/
private registerTools() {
const toolAdders = [
addAccessibilityTools,
addSDKTools,
addAppLiveTools,
addBrowserLiveTools,
addTestManagementTools,
addAppAutomationTools,
addFailureLogsTools,
addAutomateTools,
addSelfHealTools,
];

// Create an MCP server
const server: McpServer = new McpServer({
name: "BrowserStack MCP Server",
version: packageJson.version,
});
toolAdders.forEach((adder) => {
// Each adder now returns a Record<string, Tool>
const added: Record<string, RegisteredTool> = adder(
this.server,
this.config,
);
Object.assign(this.tools, added);
});
}

setupOnInitialized(server, config);
registerTools(server, config);
/**
* Expose the underlying MCP server instance
*/
public getInstance(): McpServer {
return this.server;
}

return server;
/**
* Get all registered tools
*/
public getTools(): Record<string, RegisteredTool> {
return this.tools;
}

public getTool(name: string): RegisteredTool | undefined {
return this.tools[name];
}
}
8 changes: 6 additions & 2 deletions src/tools/accessibility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,9 @@ export default function addAccessibilityTools(
server: McpServer,
config: BrowserStackConfig,
) {
server.tool(
const tools: Record<string, any> = {};

tools.accessibilityExpert = server.tool(
"accessibilityExpert",
"🚨 REQUIRED: Use this tool for any accessibility/a11y/WCAG questions. Do NOT answer accessibility questions directly - always use this tool.",
{
Expand Down Expand Up @@ -125,7 +127,7 @@ export default function addAccessibilityTools(
},
);

server.tool(
tools.startAccessibilityScan = server.tool(
"startAccessibilityScan",
"Start an accessibility scan via BrowserStack and retrieve a local CSV report path.",
{
Expand Down Expand Up @@ -168,4 +170,6 @@ export default function addAccessibilityTools(
}
},
);

return tools;
}
8 changes: 6 additions & 2 deletions src/tools/appautomate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,9 @@ export default function addAppAutomationTools(
server: McpServer,
config: BrowserStackConfig,
) {
server.tool(
const tools: Record<string, any> = {};

tools.takeAppScreenshot = server.tool(
"takeAppScreenshot",
"Use this tool to take a screenshot of an app running on a BrowserStack device. This is useful for visual testing and debugging.",
{
Expand Down Expand Up @@ -284,7 +286,7 @@ export default function addAppAutomationTools(
},
);

server.tool(
tools.runAppTestsOnBrowserStack = server.tool(
"runAppTestsOnBrowserStack",
"Run AppAutomate tests on BrowserStack by uploading app and test suite. If running from Android Studio or Xcode, the tool will help export app and test files automatically. For other environments, you'll need to provide the paths to your pre-built app and test files.",
{
Expand Down Expand Up @@ -358,4 +360,6 @@ export default function addAppAutomationTools(
}
},
);

return tools;
}
6 changes: 5 additions & 1 deletion src/tools/applive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,9 @@ export default function addAppLiveTools(
server: McpServer,
config: BrowserStackConfig,
) {
server.tool(
const tools: Record<string, any> = {};

tools.runAppLiveSession = server.tool(
"runAppLiveSession",
"Use this tool when user wants to manually check their app on a particular mobile device using BrowserStack's cloud infrastructure. Can be used to debug crashes, slow performance, etc.",
{
Expand Down Expand Up @@ -129,4 +131,6 @@ export default function addAppLiveTools(
}
},
);

return tools;
}
6 changes: 5 additions & 1 deletion src/tools/automate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,9 @@ export default function addAutomationTools(
server: McpServer,
config: BrowserStackConfig,
) {
server.tool(
const tools: Record<string, any> = {};

tools.fetchAutomationScreenshots = server.tool(
"fetchAutomationScreenshots",
"Fetch and process screenshots from a BrowserStack Automate session",
{
Expand Down Expand Up @@ -102,4 +104,6 @@ export default function addAutomationTools(
}
},
);

return tools;
}
6 changes: 5 additions & 1 deletion src/tools/bstack-sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,9 @@ export default function addSDKTools(
server: McpServer,
config: BrowserStackConfig,
) {
server.tool(
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.",
{
Expand Down Expand Up @@ -247,4 +249,6 @@ export default function addSDKTools(
}
},
);

return tools;
}
13 changes: 8 additions & 5 deletions src/tools/getFailureLogs.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
import logger from "../logger.js";
import { trackMCP } from "../lib/instrumentation.js";
import { BrowserStackConfig } from "../lib/types.js";

Expand Down Expand Up @@ -169,7 +168,9 @@ export default function registerGetFailureLogs(
server: McpServer,
config: BrowserStackConfig,
) {
server.tool(
const tools: Record<string, any> = {};

tools.getFailureLogs = server.tool(
"getFailureLogs",
"Fetch various types of logs from a BrowserStack session. Supports both automate and app-automate sessions.",
{
Expand Down Expand Up @@ -212,19 +213,19 @@ export default function registerGetFailureLogs(
);
return await getFailureLogs(args, config);
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
trackMCP(
"getFailureLogs",
server.server.getClientVersion()!,
error,
config,
);
logger.error("Failed to fetch logs: %s", message);
return {
content: [
{
type: "text",
text: `Failed to fetch logs: ${message}`,
text: `Failed to fetch failure logs: ${
error instanceof Error ? error.message : "Unknown error"
}`,
isError: true,
},
],
Expand All @@ -233,4 +234,6 @@ export default function registerGetFailureLogs(
}
},
);

return tools;
}
6 changes: 5 additions & 1 deletion src/tools/live.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@ export default function addBrowserLiveTools(
server: McpServer,
config: BrowserStackConfig,
) {
server.tool(
const tools: Record<string, any> = {};

tools.runBrowserLiveSession = server.tool(
"runBrowserLiveSession",
"Launch a BrowserStack Live session (desktop or mobile).",
LiveArgsShape,
Expand Down Expand Up @@ -145,4 +147,6 @@ export default function addBrowserLiveTools(
}
},
);

return tools;
}
6 changes: 5 additions & 1 deletion src/tools/selfheal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ export default function addSelfHealTools(
server: McpServer,
config: BrowserStackConfig,
) {
server.tool(
const tools: Record<string, any> = {};

tools.fetchSelfHealedSelectors = server.tool(
"fetchSelfHealedSelectors",
"Retrieves AI-generated, self-healed selectors for a BrowserStack Automate session to resolve flaky tests caused by dynamic DOM changes.",
{
Expand Down Expand Up @@ -69,4 +71,6 @@ export default function addSelfHealTools(
}
},
);

return tools;
}
Loading