From a8ead54159ce931817eb2cc3ac0032114e6b2ee7 Mon Sep 17 00:00:00 2001 From: tech-sushant Date: Wed, 10 Sep 2025 14:35:18 +0530 Subject: [PATCH 1/2] feat: Add build insights tool to fetch and display build details and quality gate results --- src/lib/utils.ts | 24 +++++++++ src/server-factory.ts | 2 + src/tools/build-insights.ts | 98 +++++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 src/tools/build-insights.ts diff --git a/src/lib/utils.ts b/src/lib/utils.ts index e19532c9..c12b70f7 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,5 +1,7 @@ import sharp from "sharp"; import type { ApiResponse } from "./apiClient.js"; +import { BrowserStackConfig } from "./types.js"; +import { getBrowserStackAuth } from "./get-auth.js"; export function sanitizeUrlParam(param: string): string { // Remove any characters that could be used for command injection @@ -38,3 +40,25 @@ export async function assertOkResponse( ); } } + +export async function fetchFromBrowserStackAPI( + url: string, + config: BrowserStackConfig, +): Promise { + const authString = getBrowserStackAuth(config); + const auth = Buffer.from(authString).toString("base64"); + + const res = await fetch(url, { + headers: { + Authorization: `Basic ${auth}`, + }, + }); + + if (!res.ok) { + throw new Error( + `Failed to fetch from ${url}: ${res.status} ${res.statusText}`, + ); + } + + return res.json(); +} diff --git a/src/server-factory.ts b/src/server-factory.ts index 82f93730..4a39adf8 100644 --- a/src/server-factory.ts +++ b/src/server-factory.ts @@ -15,6 +15,7 @@ import addFailureLogsTools from "./tools/get-failure-logs.js"; import addAutomateTools from "./tools/automate.js"; import addSelfHealTools from "./tools/selfheal.js"; import addAppLiveTools from "./tools/applive.js"; +import addBuildInsightsTools from "./tools/build-insights.js"; import { setupOnInitialized } from "./oninitialized.js"; import { BrowserStackConfig } from "./lib/types.js"; @@ -55,6 +56,7 @@ export class BrowserStackMcpServer { addFailureLogsTools, addAutomateTools, addSelfHealTools, + addBuildInsightsTools, ]; toolAdders.forEach((adder) => { diff --git a/src/tools/build-insights.ts b/src/tools/build-insights.ts new file mode 100644 index 00000000..a771441d --- /dev/null +++ b/src/tools/build-insights.ts @@ -0,0 +1,98 @@ +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 { BrowserStackConfig } from "../lib/types.js"; +import { fetchFromBrowserStackAPI } from "../lib/utils.js"; + +// Tool function that fetches build insights from two APIs +export async function fetchBuildInsightsTool( + args: { buildId: string }, + config: BrowserStackConfig, +): Promise { + try { + const buildUrl = `https://api-automation.browserstack.com/ext/v1/builds/${args.buildId}`; + const qualityGateUrl = `https://api-automation.browserstack.com/ext/v1/quality-gates/${args.buildId}`; + + const [buildData, qualityData] = await Promise.all([ + fetchFromBrowserStackAPI(buildUrl, config), + fetchFromBrowserStackAPI(qualityGateUrl, config), + ]); + + // Select useful fields for users + const insights = { + name: buildData.name, + status: buildData.status, + duration: buildData.duration, + user: buildData.user, + tags: buildData.tags, + alerts: buildData.alerts, + status_stats: buildData.status_stats, + failure_categories: buildData.failure_categories, + smart_tags: buildData.smart_tags, + unique_errors: buildData.unique_errors?.overview, + observability_url: buildData?.observability_url, + ci_build_url: buildData.ci_info.build_url, + quality_gate_result: qualityData.quality_gate_result, + }; + + const qualityProfiles = qualityData.quality_profiles?.map( + (profile: any) => ({ + name: profile.name, + result: profile.result, + }), + ); + + const qualityProfilesText = + qualityProfiles && qualityProfiles.length > 0 + ? `Quality Gate Profiles (respond only if explicitly requested): ${JSON.stringify(qualityProfiles, null, 2)}` + : "No Quality Gate Profiles available."; + + return { + content: [ + { + type: "text", + text: "Build insights:\n" + JSON.stringify(insights, null, 2), + }, + { type: "text", text: qualityProfilesText }, + ], + }; + } catch (error) { + logger.error("Error fetching build insights", error); + throw error; + } +} + +// Registers the fetchBuildInsights tool with the MCP server +export default function addBuildInsightsTools( + server: McpServer, + config: BrowserStackConfig, +) { + const tools: Record = {}; + + tools.fetchBuildInsights = server.tool( + "fetchBuildInsights", + "Fetches insights about a BrowserStack build by combining build details and quality gate results.", + { + buildId: z.string().describe("The build UUID of the BrowserStack build"), + }, + async (args) => { + try { + return await fetchBuildInsightsTool(args, config); + } catch (error) { + const errorMessage = + error instanceof Error ? error.message : "Unknown error"; + return { + content: [ + { + type: "text", + text: `Error during fetching build insights: ${errorMessage}`, + }, + ], + }; + } + }, + ); + + return tools; +} From d61c9a2f487a92c0c6a7738cf9e3da5f5c6163d3 Mon Sep 17 00:00:00 2001 From: tech-sushant Date: Wed, 10 Sep 2025 15:38:15 +0530 Subject: [PATCH 2/2] Update src/tools/build-insights.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/tools/build-insights.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/build-insights.ts b/src/tools/build-insights.ts index a771441d..2cf4db29 100644 --- a/src/tools/build-insights.ts +++ b/src/tools/build-insights.ts @@ -32,7 +32,7 @@ export async function fetchBuildInsightsTool( smart_tags: buildData.smart_tags, unique_errors: buildData.unique_errors?.overview, observability_url: buildData?.observability_url, - ci_build_url: buildData.ci_info.build_url, + ci_build_url: buildData.ci_info?.build_url, quality_gate_result: qualityData.quality_gate_result, };