Skip to main content
Glama
webdriverio

WebDriverIO MCP Server

Official

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
NameRequiredDescriptionDefault
browserNoBrowser to launch: chrome, firefox, edge, safari (default: chrome)chrome
headlessNo
windowWidthNo
windowHeightNo
navigationUrlNoURL to navigate to after starting the browser
capabilitiesNoAdditional W3C capabilities to merge with defaults (e.g. goog:chromeOptions args/extensions/prefs)

Implementation Reference

  • 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}`,
        }],
      };
    };
  • 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));

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/webdriverio/mcp'

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