Skip to main content
Glama
browserstack

BrowserStack MCP server

Official

runAppLiveSession

Manually test and debug mobile apps on specific devices using BrowserStack's cloud infrastructure. Install .ipa or .apk files, check for crashes, and analyze performance issues.

Instructions

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.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
appPathYesThe path to the .ipa or .apk file to install on the device. Always ask the user for the app path, do not assume it.
desiredPhoneYesThe full name of the device to run the app on. Example: 'iPhone 12 Pro' or 'Samsung Galaxy S20' or 'Google Pixel 6'. Always ask the user for the device they want to use, do not assume it.
desiredPlatformYesWhich platform to run on, examples: 'android', 'ios'. Set this based on the app path provided.
desiredPlatformVersionYesThe platform version to run the app on. Example: '12.0' for Android devices or '16.0' for iOS devices

Implementation Reference

  • Inline async handler function that executes the tool: tracks the call, invokes startAppLiveSession, and returns success/error response.
    async (args) => { try { trackMCP( "runAppLiveSession", server.server.getClientVersion()!, undefined, config, ); return await startAppLiveSession(args, config); } catch (error) { logger.error("App live session failed: %s", error); trackMCP( "runAppLiveSession", server.server.getClientVersion()!, error, config, ); return { content: [ { type: "text", text: `Failed to start app live session: ${error instanceof Error ? error.message : String(error)}`, isError: true, }, ], isError: true, }; } },
  • Zod schema for tool inputs: desiredPhone, desiredPlatformVersion, desiredPlatform, appPath.
    { desiredPhone: z .string() .describe( "The full name of the device to run the app on. Example: 'iPhone 12 Pro' or 'Samsung Galaxy S20' or 'Google Pixel 6'. Always ask the user for the device they want to use, do not assume it. ", ), desiredPlatformVersion: z .string() .describe( "Specifies the platform version to run the app on. For example, use '12.0' for Android or '16.0' for iOS. If the user says 'latest', 'newest', or similar, normalize it to 'latest'. Likewise, convert terms like 'earliest' or 'oldest' to 'oldest'.", ), desiredPlatform: z .enum(["android", "ios"]) .describe( "Which platform to run on, examples: 'android', 'ios'. Set this based on the app path provided.", ), appPath: z .string() .describe( "The path to the .ipa or .apk file to install on the device. Always ask the user for the app path, do not assume it.", ), },
  • Tool registration via server.tool call within addAppLiveTools, which is later invoked from server-factory.ts.
    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.", { desiredPhone: z .string() .describe( "The full name of the device to run the app on. Example: 'iPhone 12 Pro' or 'Samsung Galaxy S20' or 'Google Pixel 6'. Always ask the user for the device they want to use, do not assume it. ", ), desiredPlatformVersion: z .string() .describe( "Specifies the platform version to run the app on. For example, use '12.0' for Android or '16.0' for iOS. If the user says 'latest', 'newest', or similar, normalize it to 'latest'. Likewise, convert terms like 'earliest' or 'oldest' to 'oldest'.", ), desiredPlatform: z .enum(["android", "ios"]) .describe( "Which platform to run on, examples: 'android', 'ios'. Set this based on the app path provided.", ), appPath: z .string() .describe( "The path to the .ipa or .apk file to install on the device. Always ask the user for the app path, do not assume it.", ), }, async (args) => { try { trackMCP( "runAppLiveSession", server.server.getClientVersion()!, undefined, config, ); return await startAppLiveSession(args, config); } catch (error) { logger.error("App live session failed: %s", error); trackMCP( "runAppLiveSession", server.server.getClientVersion()!, error, config, ); return { content: [ { type: "text", text: `Failed to start app live session: ${error instanceof Error ? error.message : String(error)}`, isError: true, }, ], isError: true, }; } }, );
  • Helper function performing input validation and delegating to startSession for launching the session.
    export async function startAppLiveSession( args: { desiredPlatform: string; desiredPlatformVersion: string; appPath?: string; desiredPhone: string; browserstackAppUrl?: string; }, config: BrowserStackConfig, ): Promise<CallToolResult> { if (!args.desiredPlatform) { throw new Error("You must provide a desiredPlatform."); } if (!args.appPath && !args.browserstackAppUrl) { throw new Error("You must provide either appPath or browserstackAppUrl."); } if (!args.desiredPhone) { throw new Error("You must provide a desiredPhone."); } // Only validate app path if it's provided (not using browserstackAppUrl) if (args.appPath) { if (args.desiredPlatform === "android" && !args.appPath.endsWith(".apk")) { throw new Error("You must provide a valid Android app path."); } if (args.desiredPlatform === "ios" && !args.appPath.endsWith(".ipa")) { throw new Error("You must provide a valid iOS app path."); } // check if the app path exists && is readable try { if (!fs.existsSync(args.appPath)) { throw new Error("The app path does not exist."); } fs.accessSync(args.appPath, fs.constants.R_OK); } catch (error) { logger.error("The app path does not exist or is not readable: %s", error); throw new Error("The app path does not exist or is not readable."); } } const launchUrl = await startSession( { appPath: args.appPath, desiredPlatform: args.desiredPlatform as "android" | "ios", desiredPhone: args.desiredPhone, desiredPlatformVersion: args.desiredPlatformVersion, browserstackAppUrl: args.browserstackAppUrl, }, { config }, ); return { content: [ { type: "text", text: `Successfully started a session. If a browser window did not open automatically, use the following URL to start the session: ${launchUrl}`, }, ], }; }
  • Core helper implementing session start: device selection/filtering, app upload, URL generation, and browser launch.
    export async function startSession( args: StartSessionArgs, options: StartSessionOptions, ): Promise<string> { const { appPath, desiredPlatform, desiredPhone, desiredPlatformVersion, browserstackAppUrl, } = args; const { config } = options; // 1) Fetch devices for APP_LIVE const data = await getDevicesAndBrowsers(BrowserStackProducts.APP_LIVE); const all: DeviceEntry[] = data.mobile.flatMap((grp: any) => grp.devices.map((dev: any) => ({ ...dev, os: grp.os })), ); // 2) Filter by OS const osMatches = all.filter((d) => d.os === desiredPlatform); if (!osMatches.length) { throw new Error(`No devices for OS "${desiredPlatform}"`); } // 3) Select by name const nameMatches = findDeviceByName(osMatches, desiredPhone); // 4) Resolve version const versions = [...new Set(nameMatches.map((d) => d.os_version))]; const version = pickVersion(versions, desiredPlatformVersion); // 5) Final candidates for version const final = nameMatches.filter((d) => d.os_version === version); if (!final.length) { throw new Error( `No devices for version "${version}" on ${desiredPlatform}`, ); } const selected = final[0]; let note = ""; if ( version != desiredPlatformVersion && desiredPlatformVersion !== "latest" && desiredPlatformVersion !== "oldest" ) { note = `\n Note: The requested version "${desiredPlatformVersion}" is not available. Using "${version}" instead.`; } // 6) Upload app or use provided URL let app_url: string; if (browserstackAppUrl) { app_url = browserstackAppUrl; logger.info(`Using provided BrowserStack app URL: ${app_url}`); } else { if (!appPath) { throw new Error( "appPath is required when browserstackAppUrl is not provided", ); } const authString = getBrowserStackAuth(config); const [username, password] = authString.split(":"); const result = await uploadApp(appPath, username, password); app_url = result.app_url; logger.info(`App uploaded: ${app_url}`); } if (!app_url) { throw new Error("Failed to upload app. Please try again."); } // 7) Build URL & open const deviceParam = sanitizeUrlParam( selected.display_name.replace(/\s+/g, "+"), ); const params = new URLSearchParams({ os: desiredPlatform, os_version: version, app_hashed_id: app_url.split("bs://").pop() || "", scale_to_fit: "true", speed: "1", start: "true", }); const launchUrl = `https://app-live.browserstack.com/dashboard#${params.toString()}&device=${deviceParam}`; if (!envConfig.REMOTE_MCP) { openBrowser(launchUrl); } return launchUrl + note; }

Other Tools

Related Tools

Latest Blog Posts

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