MCPInstall

cdp-bridge-mcp-browser-control

Control and automate real browser sessions through CDP, preserving login state and cookies for LLM-driven interactions

Installs
218
Last 24h
—
Trending rank
—
Security
Not audited

Install

Works with every agent the skills CLI supports.

npx skills add https://github.com/reason-machines/mcp-skills --skill cdp-bridge-mcp-browser-control
  1. 01

    Install

    Run the command in your project. The CLI asks which agents to install for.

  2. 02

    Describe the task

    Ask your agent for something this skill covers. It loads cdp-bridge-mcp-browser-control automatically when relevant.

  3. 03

    Review the result

    The agent follows the SKILL.md steps, scripts and references bundled with the skill.

SKILL.md

The instructions your agent reads when the skill is triggered.

CDP Bridge MCP Browser Control

Skill by ara.so — MCP Skills collection.

Overview

CDP Bridge MCP is a Model Context Protocol server that bridges LLM clients to real, active browser sessions through Chrome DevTools Protocol (CDP) and a companion browser extension. Unlike headless automation tools, it connects to your already-open, already-logged-in browser tabs, preserving authentication state, cookies, and rendered page content.

Key differentiators:

  • Reuses real login sessions — no need to re-authenticate or transfer cookies
  • Works with current browser state — connects to tabs you already have open
  • LLM-optimized page scanning — filters HTML to preserve useful content while reducing tokens
  • Automatic CSP handling — falls back to CDP when content security policies block script injection
  • Lightweight setup — no separate browser instances or complex configuration

Installation

1. Install the MCP Server

The server is available via PyPI and can be run with uvx:

# Test with stdio mode (default)
uvx cdp-bridge@latest

# Run as HTTP server (for multi-client scenarios)
uvx cdp-bridge@latest --transport streamable-http --port 8000

2. Load Browser Extension

  1. Navigate to chrome://extensions/
  2. Enable "Developer mode"
  3. Click "Load unpacked"
  4. Select the src/cdp_bridge/tmwd_cdp_bridge folder from the repository

The extension automatically attempts to connect to 127.0.0.1:18765 (WebSocket) and retries every ~5 seconds if the server isn't running yet.

3. Configure MCP Client

For stdio mode (Claude Desktop, most local clients):

{
  "mcpServers": {
    "cdp-bridge": {
      "command": "uvx",
      "args": ["cdp-bridge@latest"]
    }
  }
}

For streamable-http mode (shared/Docker deployments):

First start the server:

uvx cdp-bridge@latest --transport streamable-http --port 8000

Then configure the client:

{
  "mcpServers": {
    "cdp-bridge": {
      "type": "streamableHttp",
      "url": "http://127.0.0.1:8000/mcp"
    }
  }
}

Claude Code:

# stdio
claude mcp add cdp-bridge uvx cdp-bridge@latest

# streamable-http
claude mcp add cdp-bridge --transport streamable-http http://127.0.0.1:8000/mcp

Codex:

# stdio
codex mcp add cdp-bridge uvx cdp-bridge@latest

# streamable-http
codex mcp add cdp-bridge --transport streamable-http --url http://127.0.0.1:8000/mcp

Available Tools

ToolPurpose
browser_get_tabsList all connected browser tabs with URLs and titles
browser_scanExtract page content as simplified HTML or plain text
browser_execute_jsRun JavaScript in the active tab
browser_switch_tabChange which tab is active for MCP operations
browser_batchExecute multiple CDP/extension commands atomically
browser_waitPoll a JavaScript condition until true or timeout
browser_navigateNavigate the active tab to a URL
browser_screenshotCapture page screenshot as base64 PNG
browser_cookiesRead cookies for the current domain

Common Usage Patterns

Get Available Tabs

# When user asks: "what tabs do I have open?"
result = await use_mcp_tool(
    server_name="cdp-bridge",
    tool_name="browser_get_tabs",
    arguments={}
)

# Result structure:
# {
#   "tabs": [
#     {"id": "tab_0", "url": "https://example.com", "title": "Example Domain"},
#     {"id": "tab_1", "url": "https://github.com", "title": "GitHub"}
#   ],
#   "active_tab": "tab_0"
# }

Scan Page Content

# Extract simplified HTML (default)
result = await use_mcp_tool(
    server_name="cdp-bridge",
    tool_name="browser_scan",
    arguments={
        "tab_id": "tab_0",
        "format": "html"  # or "text" for plain text
    }
)

# Returns cleaned HTML with scripts/styles removed
# Preserves semantic structure for LLM consumption

How browser_scan works:

  • Removes <script>, <style>, <svg>, hidden elements
  • Keeps text content, links, headings, form controls
  • Converts <img> to [Image: alt_text]
  • Ideal for reducing token usage while preserving page semantics

Execute JavaScript

# Extract data or interact with the page
result = await use_mcp_tool(
    server_name="cdp-bridge",
    tool_name="browser_execute_js",
    arguments={
        "tab_id": "tab_0",
        "code": """
            return {
                title: document.title,
                links: Array.from(document.querySelectorAll('a'))
                    .slice(0, 10)
                    .map(a => ({href: a.href, text: a.innerText}))
            };
        """
    }
)

# Result contains the returned object

Execution modes:

  1. Primary: Uses chrome.scripting.executeScript in MAIN world
  2. Fallback: Uses CDP Runtime.evaluate if CSP blocks injection

Wait for Dynamic Content

# Wait for element to appear (useful for SPAs)
result = await use_mcp_tool(
    server_name="cdp-bridge",
    tool_name="browser_wait",
    arguments={
        "tab_id": "tab_0",
        "condition": "document.querySelector('.dynamic-content') !== null",
        "timeout": 10,  # seconds
        "interval": 0.5  # poll every 500ms
    }
)

# Returns True if condition met, raises timeout error otherwise

Navigate and Screenshot

# Navigate to a URL
await use_mcp_tool(
    server_name="cdp-bridge",
    tool_name="browser_navigate",
    arguments={
        "tab_id": "tab_0",
        "url": "https://example.com"
    }
)

# Wait for page load
await use_mcp_tool(
    server_name="cdp-bridge",
    tool_name="browser_wait",
    arguments={
        "tab_id": "tab_0",
        "condition": "document.readyState === 'complete'",
        "timeout": 30
    }
)

# Capture screenshot
screenshot = await use_mcp_tool(
    server_name="cdp-bridge",
    tool_name="browser_screenshot",
    arguments={
        "tab_id": "tab_0",
        "format": "png"  # returns base64-encoded image
    }
)

Read Cookies

# Get cookies for authenticated session analysis
result = await use_mcp_tool(
    server_name="cdp-bridge",
    tool_name="browser_cookies",
    arguments={
        "tab_id": "tab_0"
    }
)

# Returns array of cookie objects:
# [{"name": "session_id", "value": "...", "domain": "example.com", ...}]

Batch Operations (Advanced)

# Execute multiple CDP commands in sequence
result = await use_mcp_tool(
    server_name="cdp-bridge",
    tool_name="browser_batch",
    arguments={
        "tab_id": "tab_0",
        "commands": [
            {
                "method": "Runtime.evaluate",
                "params": {
                    "expression": "document.title",
                    "returnByValue": True
                }
            },
            {
                "method": "Network.getCookies",
                "params": {}
            }
        ]
    }
)

# Returns array of results matching command order

Real-World Examples

Extract Article Content from Logged-In Site

# User is already logged in to medium.com
# 1. Find the article tab
tabs = await use_mcp_tool("cdp-bridge", "browser_get_tabs", {})
article_tab = next(t for t in tabs["tabs"] if "medium.com" in t["url"])

# 2. Switch to it
await use_mcp_tool("cdp-bridge", "browser_switch_tab", {"tab_id": article_tab["id"]})

# 3. Extract article text
content = await use_mcp_tool(
    "cdp-bridge",
    "browser_execute_js",
    {
        "tab_id": article_tab["id"],
        "code": """
            const article = document.querySelector('article');
            return article ? article.innerText : 'No article found';
        """
    }
)

Monitor Dashboard Data

# User has analytics dashboard open
# Poll for updated metrics every 30 seconds

while True:
    metrics = await use_mcp_tool(
        "cdp-bridge",
        "browser_execute_js",
        {
            "tab_id": "tab_0",
            "code": """
                return {
                    visitors: document.querySelector('.visitor-count')?.innerText,
                    revenue: document.querySelector('.revenue')?.innerText,
                    timestamp: Date.now()
                };
            """
        }
    )
    
    # Process metrics...
    await asyncio.sleep(30)

Fill Form in Authenticated Session

# Navigate to form page
await use_mcp_tool(
    "cdp-bridge",
    "browser_navigate",
    {"tab_id": "tab_0", "url": "https://example.com/settings"}
)

# Wait for form to load
await use_mcp_tool(
    "cdp-bridge",
    "browser_wait",
    {
        "tab_id": "tab_0",
        "condition": "document.querySelector('form#settings') !== null",
        "timeout": 10
    }
)

# Fill and submit
await use_mcp_tool(
    "cdp-bridge",
    "browser_execute_js",
    {
        "tab_id": "tab_0",
        "code": """
            const form = document.querySelector('form#settings');
            form.querySelector('input[name="email"]').value = 'user@example.com';
            form.querySelector('input[name="notifications"]').checked = true;
            form.submit();
        """
    }
)

Troubleshooting

Extension Shows "ERR_CONNECTION_REFUSED"

Normal behavior on first load. The extension retries connection every ~5 seconds. Once you invoke any MCP tool (e.g., browser_get_tabs), the server starts and the extension connects automatically within seconds.

No Tabs Appear in browser_get_tabs

  1. Verify the extension is loaded and enabled at chrome://extensions/
  2. Check the extension's service worker console for connection status
  3. Ensure MCP server is running (invoke any tool to start it in stdio mode)
  4. Confirm WebSocket server is listening on 127.0.0.1:18765

JavaScript Execution Fails with CSP Error

The extension automatically falls back to CDP Runtime.evaluate when CSP blocks chrome.scripting. If both fail:

  • Check browser console for specific CSP violations
  • Try wrapping code in (function() { ... })()
  • Avoid accessing restricted APIs (e.g., cross-origin iframes)

Tab IDs Change Unexpectedly

Tab IDs are session-based and reset when:

  • The extension reloads
  • The browser restarts
  • WebSocket reconnects

Always call browser_get_tabs before targeting a specific tab if state may have changed.

High Token Usage from browser_scan

  1. Use "format": "text" for plain text extraction (fewer tokens)
  2. Limit scope by executing JS to extract specific DOM subtrees first:
await use_mcp_tool(
    "cdp-bridge",
    "browser_execute_js",
    {
        "tab_id": "tab_0",
        "code": "document.body.innerHTML = document.querySelector('main').innerHTML"
    }
)

# Then scan the reduced page
await use_mcp_tool("cdp-bridge", "browser_scan", {"tab_id": "tab_0"})

Configuration Options

Server Launch Arguments

uvx cdp-bridge@latest [OPTIONS]

Options:
  --transport [stdio|streamable-http]  Transport mode (default: stdio)
  --port INTEGER                       HTTP port for streamable-http mode (default: 8000)

Extension Configuration

Edit src/cdp_bridge/tmwd_cdp_bridge/background.js to customize:

// WebSocket server address
const WS_URL = 'ws://127.0.0.1:18765';

// Reconnection interval (ms)
const RECONNECT_INTERVAL = 5000;

Architecture Notes

  • Transport modes: stdio for single-client (subprocess), streamable-http for multi-client (persistent server)
  • Extension communication: WebSocket (primary) + HTTP long-polling (fallback)
  • JavaScript execution: MAIN world via chrome.scripting, falls back to CDP for CSP-restricted pages
  • Session management: Each connected tab gets a unique session ID, managed by TMWebDriver

Requirements

  • Python 3.10+
  • Chrome or Chromium-based browser
  • Browser extension loaded in developer mode
  • Network access to 127.0.0.1:18765 (WebSocket) and 127.0.0.1:18766 (HTTP)

FAQ

What does the cdp-bridge-mcp-browser-control skill do?

Control and automate real browser sessions through CDP, preserving login state and cookies for LLM-driven interactions

How do I install cdp-bridge-mcp-browser-control?

Run npx skills add https://github.com/reason-machines/mcp-skills --skill cdp-bridge-mcp-browser-control in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/cdp-bridge-mcp-browser-control/ (personal) or .claude/skills/cdp-bridge-mcp-browser-control/ (project).

Which AI agents can use cdp-bridge-mcp-browser-control?

Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.

Is cdp-bridge-mcp-browser-control safe to install?

No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.

Who maintains cdp-bridge-mcp-browser-control?

It is published by reason-machines in reason-machines/mcp-skills. It has 218 recorded installs.

More from reason-machines/mcp-skills

View all →

codebase-memory-mcp-intelligence

reason-machines/mcp-skills

High-performance code intelligence MCP server that indexes codebases into knowledge graphs for structural queries, call traces, and architecture analysis

AI & Agents505 installs

playwright-mcp-server

reason-machines/mcp-skills

Browser automation MCP server using Playwright's accessibility tree for LLM-friendly web interaction

AI & Agents285 installs

tradingview-mcp-assistant

reason-machines/mcp-skills

Open the skill to read its SKILL.md instructions.

AI & Agents256 installs

lanhu-mcp-collaboration

reason-machines/mcp-skills

Open the skill to read its SKILL.md instructions.

AI & Agents245 installs

chrome-devtools-mcp-automation

reason-machines/mcp-skills

Expert guidance for Chrome DevTools MCP server - browser automation, debugging, and performance analysis for AI agents

AI & Agents239 installs

github-mcp-server

reason-machines/mcp-skills

Open the skill to read its SKILL.md instructions.

AI & Agents237 installs

Popular ai & agents skills

View category →

google-agents-cli-publish

google/agents-cli

This skill should be used when the user wants to "publish an agent", "publish my ADK agent", "register an agent with Gemini", "publish to Gemini" (formerly Gemini Enterprise), or needs guidance on the agents-cli publish gemini command. Also use when the user wants to "manage agents in Agent Registry", "list/update/delete registered agents", or "register an MCP server". Covers ADK vs A2A registration modes, programmatic and interactive usage, flag reference, auto-detection from deployment metadata, Agent Registry fleet management, and troubleshooting. Part of the agents-cli skills suite. Do NOT use for deployment (use google-agents-cli-deploy).

AI & Agents513.9K installs

google-agents-cli-eval

google/agents-cli

This skill should be used when the user wants to "run an evaluation", "evaluate my agent", "evaluate my ADK agent", "write an eval dataset", "analyze eval failures", "compare eval results", "optimize agent", or needs guidance on the Gemini platform eval methodology and the Quality Flywheel. Covers eval metrics, dataset schema, LLM-as-judge scoring, and common failure causes. Applies to any agents-cli project, whatever framework the agent is written in. Do NOT use for agent API code patterns (ADK: use google-agents-cli-adk-code), deployment (use google-agents-cli-deploy), or project scaffolding (use google-agents-cli-scaffold).

AI & Agents513.5K installs

skill-creator

anthropics/skills

Create new skills, modify and improve existing skills, and measure skill performance. Use when users want to create a skill from scratch, edit, or optimize an existing skill, run evals to test a skill, benchmark skill performance with variance analysis, or optimize a skill's description for better triggering accuracy.

OfficialAI & Agents416.4K installs

codex-pet

prime-skills/runcomfy-agent-skills

Codex Pet generator on RunComfy. Build a Codex-compatible Codex Pet spritesheet.webp + pet.json from a single reference image, drop it into ${CODEXHOME:-$HOME/.codex}/pets/ / and Codex picks it up as a custom Codex Pet next to the 8 built-ins. This skill produces the exact Codex Pet atlas Codex expects (1536x1872 PNG/WebP, 8 cols x 9 rows, 192x208 cells, 9 animation states — idle, running-right, running-left, waving, jumping, failed, waiting, running, review). Calls OpenAI GPT Image 2 edit ONCE via the local RunComfy CLI as runcomfy run openai/gpt-image-2/edit to produce a canonical Codex Pet pose, then assembles all 9 animation rows programmatically with ImageMagick micro-transforms — no Codex Pro, no $imagegen, no OPENAIAPIKEY required, only RUNCOMFYTOKEN. Triggers on "codex pet", "create codex pet", "make codex pet", "hatch codex pet", "/hatch image", "desktop pet codex", "codex pets", "spritesheet.webp", or any explicit ask to build a custom pet for OpenAI Codex.

AI & Agents402.1K installs

full-output-enforcement

leonxlnx/taste-skill

Overrides default LLM truncation behavior. Enforces complete code generation, bans placeholder patterns, and handles token-limit splits cleanly. Apply to any task requiring exhaustive, unabridged output.

AI & Agents401K installs

executing-plans

obra/superpowers

Use when executing an implementation plan in the current session as the implementer yourself — your human partner chose inline execution, or no subagent tool is available

AI & Agents245.7K installs