start_browser
Launch a browser session for automated web testing and interaction. Configure browser type, window size, and headless mode to initiate web automation workflows.
Instructions
starts a browser session (Chrome, Firefox, Edge, Safari) and sets it to the current state. Prefer headless: true unless the user explicitly asks to see the browser.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| browser | No | Browser to launch: chrome, firefox, edge, safari (default: chrome) | chrome |
| headless | No | ||
| windowWidth | No | ||
| windowHeight | No | ||
| navigationUrl | No | URL to navigate to after starting the browser | |
| capabilities | No | Additional W3C capabilities to merge with defaults (e.g. goog:chromeOptions args/extensions/prefs) |
Implementation Reference
- src/tools/browser.tool.ts:55-219 (handler)The implementation of the start_browser tool handler, which uses WebdriverIO to initialize a browser session and updates local state.
export const startBrowserTool: ToolCallback = async ({ browser = 'chrome', headless = true, windowWidth = 1920, windowHeight = 1080, navigationUrl, capabilities: userCapabilities = {} }: { browser?: SupportedBrowser; headless?: boolean; windowWidth?: number; windowHeight?: number; navigationUrl?: string; capabilities?: Record<string, unknown>; }): Promise<CallToolResult> => { const browserDisplayNames: Record<SupportedBrowser, string> = { chrome: 'Chrome', firefox: 'Firefox', edge: 'Edge', safari: 'Safari', }; const selectedBrowser = browser; const headlessSupported = selectedBrowser !== 'safari'; const effectiveHeadless = headless && headlessSupported; const chromiumArgs = [ `--window-size=${windowWidth},${windowHeight}`, '--no-sandbox', '--disable-search-engine-choice-screen', '--disable-infobars', '--log-level=3', '--use-fake-device-for-media-stream', '--use-fake-ui-for-media-stream', '--disable-web-security', '--allow-running-insecure-content', ]; // Add headless argument if enabled if (effectiveHeadless) { chromiumArgs.push('--headless=new'); chromiumArgs.push('--disable-gpu'); chromiumArgs.push('--disable-dev-shm-usage'); } const firefoxArgs: string[] = []; if (effectiveHeadless && selectedBrowser === 'firefox') { firefoxArgs.push('-headless'); } const capabilities: Record<string, any> = { acceptInsecureCerts: true, }; switch (selectedBrowser) { case 'chrome': capabilities.browserName = 'chrome'; capabilities['goog:chromeOptions'] = { args: chromiumArgs }; break; case 'edge': capabilities.browserName = 'msedge'; capabilities['ms:edgeOptions'] = { args: chromiumArgs }; break; case 'firefox': capabilities.browserName = 'firefox'; if (firefoxArgs.length > 0) { capabilities['moz:firefoxOptions'] = { args: firefoxArgs }; } break; case 'safari': capabilities.browserName = 'safari'; break; } const mergeCapabilityOptions = (defaultOptions: unknown, customOptions: unknown) => { if (!defaultOptions || typeof defaultOptions !== 'object' || !customOptions || typeof customOptions !== 'object') { return customOptions ?? defaultOptions; } const defaultRecord = defaultOptions as Record<string, unknown>; const customRecord = customOptions as Record<string, unknown>; const merged = { ...defaultRecord, ...customRecord }; if (Array.isArray(defaultRecord.args) || Array.isArray(customRecord.args)) { merged.args = [ ...(Array.isArray(defaultRecord.args) ? defaultRecord.args : []), ...(Array.isArray(customRecord.args) ? customRecord.args : []), ]; } return merged; }; const mergedCapabilities: Record<string, unknown> = { ...capabilities, ...userCapabilities, 'goog:chromeOptions': mergeCapabilityOptions(capabilities['goog:chromeOptions'], userCapabilities['goog:chromeOptions']), 'ms:edgeOptions': mergeCapabilityOptions(capabilities['ms:edgeOptions'], userCapabilities['ms:edgeOptions']), 'moz:firefoxOptions': mergeCapabilityOptions(capabilities['moz:firefoxOptions'], userCapabilities['moz:firefoxOptions']), }; for (const [key, value] of Object.entries(mergedCapabilities)) { if (value === undefined) { delete mergedCapabilities[key]; } } const wdioBrowser = await remote({ capabilities: mergedCapabilities, }); const { sessionId } = wdioBrowser; state.browsers.set(sessionId, wdioBrowser); state.sessionMetadata.set(sessionId, { type: 'browser', capabilities: wdioBrowser.capabilities, isAttached: false, }); // If replacing an active session, close its history and append transition sentinel if (state.currentSession && state.currentSession !== sessionId) { const outgoing = state.sessionHistory.get(state.currentSession); if (outgoing) { outgoing.steps.push({ index: outgoing.steps.length + 1, tool: '__session_transition__', params: { newSessionId: sessionId }, status: 'ok', durationMs: 0, timestamp: new Date().toISOString(), }); outgoing.endedAt = new Date().toISOString(); } } state.sessionHistory.set(sessionId, { sessionId, type: 'browser', startedAt: new Date().toISOString(), capabilities: wdioBrowser.capabilities as Record<string, unknown>, steps: [], }); state.currentSession = sessionId; let sizeNote = ''; try { await wdioBrowser.setWindowSize(windowWidth, windowHeight); } catch (e) { sizeNote = `\nNote: Unable to set window size (${windowWidth}x${windowHeight}). ${e}`; } // Navigate to URL if provided if (navigationUrl) { await wdioBrowser.url(navigationUrl); } const modeText = effectiveHeadless ? 'headless' : 'headed'; const browserText = browserDisplayNames[selectedBrowser]; const urlText = navigationUrl ? ` and navigated to ${navigationUrl}` : ''; const headlessNote = headless && !headlessSupported ? '\nNote: Safari does not support headless mode. Started in headed mode.' : ''; return { content: [{ type: 'text', text: `${browserText} browser started in ${modeText} mode with sessionId: ${sessionId} (${windowWidth}x${windowHeight})${urlText}${headlessNote}${sizeNote}`, }], }; }; - src/tools/browser.tool.ts:12-23 (schema)The ToolDefinition containing the name, description, and inputSchema for start_browser.
export const startBrowserToolDefinition: ToolDefinition = { name: 'start_browser', description: 'starts a browser session (Chrome, Firefox, Edge, Safari) and sets it to the current state. Prefer headless: true unless the user explicitly asks to see the browser.', inputSchema: { browser: browserSchema.describe('Browser to launch: chrome, firefox, edge, safari (default: chrome)'), headless: z.boolean().optional().default(true), windowWidth: z.number().min(400).max(3840).optional().default(1920), windowHeight: z.number().min(400).max(2160).optional().default(1080), navigationUrl: z.string().optional().describe('URL to navigate to after starting the browser'), capabilities: z.record(z.string(), z.unknown()).optional().describe('Additional W3C capabilities to merge with defaults (e.g. goog:chromeOptions args/extensions/prefs)'), }, }; - src/server.ts:96-96 (registration)The registration of the start_browser tool in the MCP server setup.
registerTool(startBrowserToolDefinition, withRecording('start_browser', startBrowserTool));