Retry Logic for Chrome Connection Failures in MCP: A Deep Dive into chrome-devtools-mcp

The Chrome DevTools MCP server does not implement automatic retry logic for Chrome connection failures, requiring clients to handle reconnection attempts manually.

The ChromeDevTools/chrome-devtools-mcp repository provides a Model Context Protocol (MCP) server for Chrome automation, but understanding its retry logic for Chrome connection failures is critical for building resilient applications. Unlike many networking libraries that offer built-in exponential backoff, this MCP implementation treats connection errors as terminal failures that must be handled by the consuming client.

How MCP Handles Chrome Connection Failures

The MCP server treats Chrome connection failures as hard errors rather than transient issues warranting automatic retry. According to the source code in src/browser.ts, both primary connection entry points—ensureBrowserConnected for attaching to existing browsers and ensureBrowserLaunched for spawning new instances—implement single-attempt logic with immediate error propagation.

Attaching to Existing Chrome Instances

The ensureBrowserConnected function attempts to connect to a running Chrome instance via puppeteer.connect exactly once. Located at lines 119-128 in src/browser.ts, the implementation wraps the connection attempt in a try-catch block that immediately re-throws any encountered errors without retry logic:

// src/browser.ts
try {
  browser = await puppeteer.connect(connectOptions);
} catch (err) {
  throw new Error(
    'Could not connect to Chrome. Check if Chrome is running and remote debugging is enabled by going to chrome://inspect/#remote-debugging.',
    { cause: err },
  );
}

Launching New Browser Instances

Similarly, ensureBrowserLaunched at lines 92-108 attempts puppeteer.launch once, catching errors only to add contextual information before re-throwing. The function specifically checks for "The browser is already running" errors to provide helpful guidance about using the --isolated flag, but does not implement any retry mechanism:

// src/browser.ts
try {
  const browser = await puppeteer.launch({ … });

  return browser;
} catch (error) {
  if (userDataDir && (error as Error).message.includes('The browser is already running')) {
    throw new Error(
      `The browser is already running for ${userDataDir}. Use --isolated to run multiple browser instances.`,
      { cause: error },
    );
  }
  throw error;
}

Error Propagation in the MCP Architecture

The surrounding MCP logic in src/main.ts reinforces the no-retry policy. The getContext function awaits ensureBrowserConnected or ensureBrowserLaunched and allows any thrown errors to surface directly to the client. This design delegates all retry responsibility to the consumer of the MCP server, ensuring that connection failures are immediately visible rather than hidden behind retry loops that might mask underlying configuration issues.

Implementing Custom Retry Logic for MCP Chrome Connections

Since the chrome-devtools-mcp server does not provide built-in retry logic for Chrome connection failures, applications requiring resilience must implement their own wrapper functions. Below is an illustrative implementation that adds exponential backoff around the MCP connection functions:

import {ensureBrowserConnected} from './browser.js';

async function connectWithRetry(
  options: ConnectOptions, 
  maxAttempts = 3, 
  delayMs = 1000
): Promise<Browser> {
  for (let attempt = 1; attempt <= maxAttempts; ++attempt) {
    try {
      return await ensureBrowserConnected(options);
    } catch (err) {
      if (attempt === maxAttempts) throw err; // Final attempt failed
      console.warn(
        `Chrome connection attempt ${attempt} failed – retrying in ${delayMs}ms`
      );
      await new Promise(res => setTimeout(res, delayMs));
      // Optional: implement exponential backoff here
      delayMs *= 2;
    }
  }
  throw new Error('Unreachable');
}

This pattern allows clients to handle transient network issues or timing problems where Chrome might not be fully initialized when the MCP server first attempts connection.

Summary

  • The ChromeDevTools/chrome-devtools-mcp server does not implement automatic retry logic for Chrome connection failures.
  • Both ensureBrowserConnected and ensureBrowserLaunched in src/browser.ts attempt connection exactly once and immediately propagate errors to the caller.
  • Error handling focuses on providing contextual error messages (e.g., checking if Chrome is running or if the browser is already active) rather than retrying.
  • Clients requiring resilience must implement custom retry wrappers with exponential backoff or circuit breakers at the application level.

Frequently Asked Questions

Does the Chrome DevTools MCP server automatically retry failed connections?

No. The MCP server treats connection failures as terminal errors. Both the ensureBrowserConnected and ensureBrowserLaunched functions in src/browser.ts implement single-attempt logic with immediate error propagation, requiring clients to handle any retry behavior.

What error messages does MCP provide when Chrome connection fails?

When puppeteer.connect fails in ensureBrowserConnected, the server throws an error advising users to check if Chrome is running and if remote debugging is enabled via chrome://inspect/#remote-debugging. For ensureBrowserLaunched, it detects "browser already running" errors and suggests using the --isolated flag.

How can I add retry logic to my MCP Chrome connection code?

Implement a wrapper function around ensureBrowserConnected or ensureBrowserLaunched that catches connection errors and retries with exponential backoff. The MCP server exposes these functions from src/browser.ts, allowing you to create custom resilience patterns while the core server maintains its single-attempt design.

Where is the connection logic located in the chrome-devtools-mcp repository?

The primary connection logic resides in src/browser.ts, specifically within the ensureBrowserConnected function (lines 119-128) for attaching to existing Chrome instances and ensureBrowserLaunched (lines 92-108) for launching new browsers. The getContext function in src/main.ts orchestrates these calls without adding retry logic.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →