Skip to main content
Glama

attach-cdp

npm version CI license

Drive the Chrome you are already logged into — from your terminal, or from an AI agent.

Most browser automation starts a new browser: empty profile, no cookies, no sessions, so the first thing it hits is a login wall. attach-cdp does the opposite. It finds the Chromium browser that is already running on your machine, connects to it over the DevTools Protocol, and works with your real tabs.

It ships as two things:

attach-cdp

A dependency-free CLI: list tabs, evaluate JavaScript, navigate, click, screenshot, print to PDF, send raw CDP commands

attach-cdp-mcp

An MCP bridge that points chrome-devtools-mcp at your running browser instead of a private one

$ attach-cdp list
  #0  Inbox (12) - you@example.com - Gmail
      https://mail.google.com/mail/u/0/#inbox
  #1  Pull requests · Dr-SherBaz/attach-cdp
      https://github.com/Dr-SherBaz/attach-cdp/pulls

$ attach-cdp eval "#0" "document.title"
Inbox (12) - you@example.com - Gmail

Why this exists

Since Chrome 136, a browser started with the default user-data directory refuses to serve the HTTP discovery endpoints (/json/version, /json/list). They answer 404 — but the WebSocket debugger endpoint still works, and Chrome still writes the endpoint into DevToolsActivePort inside the profile.

That single detail breaks most "connect to my running browser" recipes, and it is the reason an agent ends up with a second, logged-out window. attach-cdp reads that file directly and never asks the HTTP endpoints for permission:

<user-data-dir>/DevToolsActivePort
  9222
  /devtools/browser/f1b4c93d-...
        │
        └──> ws://127.0.0.1:9222/devtools/browser/f1b4c93d-...

No dependencies. No bundled protocol typings. Just Node's built-in WebSocket.

Related MCP server: Browser Controller

Requirements

  • Node.js 22 or newer (uses the global WebSocket; no ws package)

  • A Chromium-family browser with remote debugging enabled: Chrome, Chromium, Chrome Beta/Dev/Canary, Brave, Vivaldi or Edge

  • For the MCP bridge only: npx (ships with Node) and network access to fetch chrome-devtools-mcp

Enable remote debugging in your browser

Quit the browser completely first — launching it again while it is running ignores new flags.

# Windows
& "C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222
# macOS
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --remote-debugging-port=9222
# Linux
google-chrome --remote-debugging-port=9222

Chrome 144+ also lets you turn this on from chrome://inspect/#remote-debugging without restarting, if your build offers the toggle.

Keep the debug port on 127.0.0.1. Anyone who can reach it can drive your logged-in browser.

Install

npm install -g attach-cdp
# or run without installing
npx attach-cdp doctor

From source, if you want to hack on it:

git clone https://github.com/Dr-SherBaz/attach-cdp.git
cd attach-cdp
npm link          # puts attach-cdp and attach-cdp-mcp on your PATH

Without npm link, run the entry points directly:

node bin/attach-cdp.mjs doctor
node bin/attach-cdp-mcp.mjs

Quick start

attach-cdp doctor                 # is there a browser, can we talk to it?
attach-cdp list                   # what tabs are open?
attach-cdp text "#0" | head         # visible text of a tab
attach-cdp eval "#0" "document.title"
attach-cdp shot "#0" page.png --full
attach-cdp close iana.org         # close a tab by URL fragment

doctor is the command to run when anything looks wrong. It shows the endpoint it found, where it found it, the browser version, and every open tab.

Commands

Command

Description

doctor

Diagnose discovery, connection and tab access

list

List open tabs (--json, --wide)

text <tab>

Print the visible text of a tab

eval <tab> <expression>

Evaluate JavaScript (--file, --stdin, --timeout)

call <tab> <Method> [json]

Send a raw CDP command (--params, --params-file)

nav <tab> <url>

Navigate and wait for the document

open <url>

Open a new tab

shot <tab> [file]

Screenshot (--full, --format png|jpeg|webp, --quality)

pdf <tab> [file]

Print to PDF (--landscape)

click <tab> <selector>

Click the first element matching a CSS selector

wait <tab> <expression>

Poll until an expression is truthy (--timeout)

close <tab>

Close a tab

mcp [args…]

Start the MCP bridge (see below)

Selecting a tab

Selector

Meaning

#0

Index from attach-cdp list

1DD7F6D10528D482FB5CBDFF9E4BED9C

Exact target id

mail.google.com

Case-insensitive substring of the URL

Pull requests

Case-insensitive substring of the title

URL matches win over title matches; among equals, the first tab in browser order wins.

Global options

Option

Meaning

--ws <url>

Browser WebSocket endpoint (or CDP_WS_ENDPOINT)

--port <n>

Query /json/version on a port (or CDP_PORT)

--json

Machine-readable output

--timeout <ms>

Per-operation timeout (default 30000)

--quiet

Drop the "attached via …" note on stderr

-h, -v

Help, version

Endpoint precedence: --ws → --port → DevToolsActivePort scan.

On Windows PowerShell, JSON arguments lose their quotes on the way to a native executable. Use --params-file params.json instead of inlining JSON.

MCP bridge for AI agents

The bridge exists to answer one question: how do I let an agent use my logged-in browser?

attach-cdp mcp            # or: attach-cdp-mcp

It resolves the endpoint, then execs chrome-devtools-mcp --wsEndpoint <url>. If no browser is found it falls back to launching a private profile (override with ATTACH_CDP_FALLBACK_PROFILE, disable with --no-fallback / buildBridgeCommand({ fallback: false })).

OpenCode

~/.config/opencode/opencode.json:

{
  "mcp": {
    "servers": {
      "chrome-devtools": {
        "type": "local",
        "command": ["npx", "-y", "attach-cdp", "mcp"]
      }
    }
  }
}

Claude Code

claude mcp add chrome-devtools -- npx -y attach-cdp mcp

Claude Desktop / Cursor / Zed

{
  "mcpServers": {
    "chrome-devtools": {
      "command": "npx",
      "args": ["-y", "attach-cdp", "mcp"]
    }
  }
}

Restart the client after changing MCP configuration: the server reads the endpoint once, at startup.

Programmatic API

import { resolveEndpoint, Connection, listTargets, attach, evaluate } from "attach-cdp";

const endpoint = await resolveEndpoint();          // uses DevToolsActivePort
const conn = await Connection.open(endpoint.wsEndpoint);

const tabs = await listTargets(conn);
const session = await attach(conn, tabs[0].targetId);
console.log(await evaluate(conn, session, "document.title"));

conn.close();

Everything is exported from src/index.js: connection handling, target listing, evaluate, screenshots, PDF, navigation, clicking, polling and endpoint discovery.

Security notes

Attaching means exactly what it sounds like: full control of a browser profile that is signed in to your accounts.

  • Leave the debug port bound to 127.0.0.1. Never publish it, never forward it to another machine.

  • Any local process can use an open debug port — enable it for the session, not permanently.

  • An agent wired to this bridge can read anything those tabs can read. Treat the MCP client with the same trust you give the browser.

  • Prefer a dedicated browser profile when automating something sensitive, and use --user-data-dir for that profile.

  • This project never sends your data anywhere. It talks to 127.0.0.1 and nothing else — the only network fetch in the codebase is /json/version on a local port, plus npx fetching chrome-devtools-mcp.

Troubleshooting

Symptom

Cause

Fix

404 from /json/version

Chrome 136+ hides HTTP discovery for the default profile

Ignore it: attach-cdp uses DevToolsActivePort. Do not pass --port

Nothing is listening on 127.0.0.1:9222

Browser not started with the flag

Quit the browser fully, relaunch with --remote-debugging-port=9222

No debug endpoint found

No DevToolsActivePort in any known profile

Run attach-cdp doctor to see which directories were checked

Flag ignored, port still closed

Browser was already running when you relaunched it

Quit every window (and any background process) first

Could not connect to ws://…

Stale DevToolsActivePort from a crashed session

Restart the browser

MCP tools see about:blank only

Client launched its own browser

Point the client at attach-cdp-mcp, not chrome-devtools-mcp

Tab selector matches nothing

Duplicate tabs

Use #N from attach-cdp list

Set ATTACH_CDP_DEBUG=1 to print stack traces.

Development

npm test              # unit tests + live integration tests (skipped when no browser)
npm run check         # syntax check the entry points
CDP_WS_ENDPOINT=... npm test   # force the integration tests against a known endpoint

Layout:

src/endpoint.js    discovery: profiles, DevToolsActivePort, ports
src/cdp.js         protocol client and page helpers
src/match.js       tab selection
src/cli.js         argument parsing and command dispatch
src/mcp-bridge.js  chrome-devtools-mcp launcher
bin/               the two entry points
test/              node:test suites

License

MIT © Muhammad Sher Baz Ali

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables CLI coding agents to interact with your live browser tabs via MCP, using your real sessions and cookies without a sandbox.
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables any MCP-compatible AI agent to drive your own Chrome browser with your existing login state, filling forms, clicking elements, fetching data, and handling captchas without API keys or re-authentication.
    446 npm
    567
    MIT