Skip to main content
Glama

BrowserStack MCP server

Official
get-failure-logs.ts6.49 kB
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z } from "zod"; import { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; import { trackMCP } from "../lib/instrumentation.js"; import { BrowserStackConfig } from "../lib/types.js"; import { retrieveNetworkFailures, retrieveSessionFailures, retrieveConsoleFailures, } from "./failurelogs-utils/automate.js"; import { retrieveDeviceLogs, retrieveAppiumLogs, retrieveCrashLogs, } from "./failurelogs-utils/app-automate.js"; import { AppAutomateLogType, AutomateLogType, SessionType, } from "../lib/constants.js"; type LogType = AutomateLogType | AppAutomateLogType; type SessionTypeValues = SessionType; // Main log fetcher function export async function getFailureLogs( args: { sessionId: string; buildId?: string; logTypes: LogType[]; sessionType: SessionTypeValues; }, config: BrowserStackConfig, ): Promise<CallToolResult> { const results: CallToolResult["content"] = []; const errors: string[] = []; let validLogTypes: LogType[] = []; if (!args.sessionId) { throw new Error("Session ID is required"); } if (args.sessionType === SessionType.AppAutomate && !args.buildId) { throw new Error("Build ID is required for app-automate sessions"); } // Validate log types and collect errors validLogTypes = args.logTypes.filter((logType) => { const isAutomate = Object.values(AutomateLogType).includes( logType as AutomateLogType, ); const isAppAutomate = Object.values(AppAutomateLogType).includes( logType as AppAutomateLogType, ); if (!isAutomate && !isAppAutomate) { errors.push( `Invalid log type '${logType}'. Valid log types are: ${[ ...Object.values(AutomateLogType), ...Object.values(AppAutomateLogType), ].join(", ")}`, ); return false; } if (args.sessionType === SessionType.Automate && !isAutomate) { errors.push( `Log type '${logType}' is only available for app-automate sessions.`, ); return false; } if (args.sessionType === SessionType.AppAutomate && !isAppAutomate) { errors.push( `Log type '${logType}' is only available for automate sessions.`, ); return false; } return true; }); if (validLogTypes.length === 0) { return { content: [ { type: "text", text: `No valid log types found for ${args.sessionType} session.\nErrors encountered:\n${errors.join("\n")}`, isError: true, }, ], }; } let response; // eslint-disable-next-line no-useless-catch try { for (const logType of validLogTypes) { switch (logType) { case AutomateLogType.NetworkLogs: { response = await retrieveNetworkFailures(args.sessionId, config); results.push({ type: "text", text: response }); break; } case AutomateLogType.SessionLogs: { response = await retrieveSessionFailures(args.sessionId, config); results.push({ type: "text", text: response }); break; } case AutomateLogType.ConsoleLogs: { response = await retrieveConsoleFailures(args.sessionId, config); results.push({ type: "text", text: response }); break; } case AppAutomateLogType.DeviceLogs: { response = await retrieveDeviceLogs( args.sessionId, args.buildId!, config, ); results.push({ type: "text", text: response }); break; } case AppAutomateLogType.AppiumLogs: { response = await retrieveAppiumLogs( args.sessionId, args.buildId!, config, ); results.push({ type: "text", text: response }); break; } case AppAutomateLogType.CrashLogs: { response = await retrieveCrashLogs( args.sessionId, args.buildId!, config, ); results.push({ type: "text", text: response }); break; } } } } catch (error) { throw error; } if (errors.length > 0) { results.push({ type: "text", text: `Errors encountered:\n${errors.join("\n")}`, isError: true, }); } return { content: results }; } // Register tool with the MCP server export default function registerGetFailureLogs( server: McpServer, config: BrowserStackConfig, ) { 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.", { sessionType: z .enum([SessionType.Automate, SessionType.AppAutomate]) .describe( "Type of BrowserStack session. Must be explicitly provided by the user.", ), sessionId: z .string() .describe( "The BrowserStack session ID. Must be explicitly provided by the user.", ), buildId: z .string() .optional() .describe( "Required only when sessionType is 'app-automate'. If sessionType is 'app-automate', always ask the user to provide the build ID before proceeding.", ), logTypes: z .array( z.enum([ AutomateLogType.NetworkLogs, AutomateLogType.SessionLogs, AutomateLogType.ConsoleLogs, AppAutomateLogType.DeviceLogs, AppAutomateLogType.AppiumLogs, AppAutomateLogType.CrashLogs, ]), ) .describe("The types of logs to fetch."), }, async (args) => { try { trackMCP( "getFailureLogs", server.server.getClientVersion()!, undefined, config, ); return await getFailureLogs(args, config); } catch (error) { trackMCP( "getFailureLogs", server.server.getClientVersion()!, error, config, ); return { content: [ { type: "text", text: `Failed to fetch failure logs: ${ error instanceof Error ? error.message : "Unknown error" }`, isError: true, }, ], isError: true, }; } }, ); return tools; }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/browserstack/mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server