npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

chromium-cdp-mcp

v1.0.0

Published

MCP server (TypeScript) that drives ANY Chromium-based browser (Chrome, Edge, Brave, Opera, Vivaldi, plain Chromium, headless launchers) over the Chrome DevTools Protocol. Pass any --remote-debugging-port and get full automation: navigate, click, fill, sc

Downloads

161

Readme

chromium-cdp-mcp

Model Context Protocol server that lets an AI assistant drive any Chromium-based browser via the Chrome DevTools Protocol. No Puppeteer, no Playwright — a thin layer of native WebSocket directly to the browser's --remote-debugging-port.

What it is

A standalone MCP server (TypeScript). Once an MCP-aware client (Claude Desktop, Claude Code, Cursor, Windsurf, Cline, Continue.dev, Zed, Codex CLI, Goose, …) loads it, the AI can:

  • navigate, click, fill, scroll, type, select options, take screenshots
  • run arbitrary JavaScript and receive the real return value
  • handle JS dialogs (alert / confirm / prompt / beforeunload)
  • click inside cross-origin iframes (Cloudflare Turnstile, reCAPTCHA, embed widgets)
  • manage tabs, override the viewport, send raw CDP commands

The server is browser-agnostic: every tool takes a port argument and connects to whatever Chromium-based browser is listening on that port.

What it is NOT

  • Not a profile / fingerprint manager. For antidetect profile creation, proxies, cookies, and batched profile orchestration use a separate MCP such as undetectable-local-api-mcp-ts.
  • Not a browser launcher. You start the browser yourself (or via the antidetect software); this server attaches.

Install

From npm

# in your MCP client config — auto-fetches and runs
npx -y chromium-cdp-mcp

From source

git clone https://github.com/<your-org>/chromium-cdp-mcp
cd chromium-cdp-mcp
npm install
npm run build
node dist/server.js     # or `npm start`

Requires Node.js ≥ 22 (native WebSocket).

MCP client config

Same shape for every client. Example (claude_desktop_config.json etc.):

{
  "mcpServers": {
    "chromium-cdp": {
      "command": "npx",
      "args": ["-y", "chromium-cdp-mcp"]
    }
  }
}

For a local checkout:

{
  "mcpServers": {
    "chromium-cdp": {
      "command": "node",
      "args": ["/absolute/path/to/MCP-CDP/dist/server.js"]
    }
  }
}

Launch a browser with CDP enabled

The server connects to an already-running Chromium instance via its remote debugging port. Start one of these first:

Chrome / Chromium

# Linux / macOS
google-chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-cdp

# Windows (PowerShell or cmd)
"C:\Program Files\Google\Chrome\Application\chrome.exe" ^
  --remote-debugging-port=9222 ^
  --user-data-dir="%TEMP%\chrome-cdp"

Microsoft Edge

"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe" ^
  --remote-debugging-port=9222 ^
  --user-data-dir="%TEMP%\edge-cdp"

Brave / Opera / Vivaldi / Yandex Browser

Same --remote-debugging-port=PORT flag — every Chromium fork supports it.

Puppeteer / Playwright launchers

// Puppeteer
const browser = await puppeteer.launch({
  args: ["--remote-debugging-port=9222"],
});

// Playwright (chromium)
const browser = await chromium.launch({
  args: ["--remote-debugging-port=9222"],
});

Use a fresh profile

--user-data-dir points to a clean profile directory. Without it, Chrome refuses to enable remote debugging on your default profile (a 122+ security restriction).

Verify the port is live

curl http://127.0.0.1:9222/json/version

If you see JSON with webSocketDebuggerUrl, you're ready.

Connection block

Every tool accepts the same connection fields:

| Field | Type | Description | | -------------- | -------- | ---------------------------------------------------------------------------- | | port | number | The browser's --remote-debugging-port. Required. | | host | string | Default 127.0.0.1. | | target_id | string | Explicit page targetId from list_tabs. Skips auto-pick. | | url_contains | string | Pick the first page whose URL contains this substring. | | tab_index | number | Pick page by index in Target.getTargets order. |

Auto-pick (when none of target_id / url_contains / tab_index is given): the first attached page, falling back to the first page in the target list.

Tools

Connection / tabs

| Tool | What it does | | ----------- | --------------------------------------------------------------------- | | connect | Probe /json/version + /json/list. Diagnostic. | | list_tabs | Target.getTargets. Returns {targetId, type, url, title, attached}.| | new_tab | Open a new tab. Optional url. Returns the new targetId. | | close_tab | Close the tab specified by target_id. |

Navigation

| Tool | What it does | | ---------- | ---------------------------------------------------------------------------- | | navigate | Page.navigate + best-effort wait for load. Returns final URL. | | back | history.back(). | | forward | history.forward(). | | reload | Page.reload, optional ignore_cache. |

JavaScript

| Tool | What it does | | --------------- | ------------------------------------------------------------------------------------------------------- | | evaluate | Runtime.evaluate with awaitPromise=true, returnByValue=true. Returns the actual value. | | get_page_html | document.documentElement.outerHTML. | | get_url | location.href. |

DOM interactions

| Tool | What it does | | -------------------------- | ----------------------------------------------------------------------------------------------- | | click | Real mouse press+release at the element's center. CSS or XPath selector. | | click_at | Real mouse press+release at raw viewport (x, y). | | click_iframe | Real click inside any iframe (cross-origin friendly). dx / dy offsets, default center. | | click_and_accept_dialog | Click AND auto-handle any alert / confirm / prompt dialog the click triggers. | | handle_dialog | Handle a currently-open JS dialog. accept, optional prompt_text. | | fill | Focus + Input.insertText. Clears existing value unless append=true. Supports unicode. | | select_option | Set <select> value + dispatch input and change events so frameworks react. | | focus | el.focus(). | | scroll_to | Scroll element into view (center). Returns its bounding rect. | | scroll | window.scrollTo(x,y) (absolute) or scrollBy(dx,dy) (relative). | | press_key | Input.dispatchKeyEventEnter / Tab / Escape / arrows / printable chars / unicode. | | wait_for | Poll for a selector until it appears (or timeout). |

Capture / emulation

| Tool | What it does | | -------------- | -------------------------------------------------------------------------------------------------- | | screenshot | Page.captureScreenshot → file. full_page, format (png / jpeg), quality. | | set_viewport | Emulation.setDeviceMetricsOverride. Mobile emulation. clear: true to reset. |

Escape hatch

| Tool | What it does | | ----- | -------------------------------------------------------------------------------------------------- | | raw | Send any CDP method directly. For things not exposed as a dedicated tool: Network.*, Storage.*, Fetch.*, Target.activateTarget, etc. |

Selectors

Any selector starting with / or (/ is treated as XPath. Everything else is treated as CSS. Examples:

input[name="email"]                    # CSS
#submit                                # CSS
//button[contains(.,"Войти")]          # XPath
(//a[@class="title"])[3]               # XPath

Quickstart for an AI assistant

A natural step sequence for filling and submitting a form looks like this:

1. connect            { port: 9222 }                                # confirm browser is alive
2. navigate           { port: 9222, url: "https://example.com" }    # load page
3. wait_for           { port: 9222, selector: "input#email" }       # wait for hydration
4. fill               { port: 9222, selector: "input#email", text: "[email protected]" }
5. fill               { port: 9222, selector: "input#password", text: "<entered by user>" }
6. click_and_accept_dialog
                      { port: 9222, selector: "#submit", accept: true }
7. wait_for           { port: 9222, selector: ".dashboard" }
8. screenshot         { port: 9222, path: "/tmp/dashboard.png" }

Integration with antidetect browsers

Antidetect / multi-profile browsers expose a remote-debugging port per running profile. Hand that port to this MCP and it can drive the underlying browser without caring about fingerprinting, proxies, or profile state — those are managed by the antidetect's own MCP / API.

Example: Undetectable + chromium-cdp-mcp

Undetectable's local API (and its undetectable-local-api-mcp-ts wrapper) returns a debug_port whenever a profile is started:

// undetectable-local-api-mcp-ts → start_profile response
{
  "code": 0,
  "data": {
    "debug_port": "52967",
    "websocket_link": "ws://127.0.0.1:52967/devtools/browser/<id>",
    "name": "my-profile"
  },
  "status": "success"
}

Feed 52967 straight into this MCP's tools:

// chromium-cdp-mcp → navigate
{ "port": 52967, "url": "https://example.com" }

This split keeps responsibilities clean:

  • undetectable-local-api-mcp-ts — create profile, set proxy, set OS/browser, start / stop, batch operations, cookies, fingerprint configs.
  • chromium-cdp-mcp — everything the AI does inside the browser session.

The same pattern works for any antidetect browser or headless launcher that publishes a webSocketDebuggerUrl on a known port (AdsPower, GoLogin, Multilogin, Puppeteer, Playwright …).

Env

| Variable | Default | Notes | | ------------- | ------- | ------------------------------------------------ | | CDP_TIMEOUT | 30 | Per-command timeout in seconds. |

Known limitations

  • Native WebSocket required. Node ≥ 22.
  • Cross-origin iframe selectors. click / fill / select_option use a selector evaluated against the main page DOM. For elements inside a cross-origin iframe (Cloudflare Turnstile, reCAPTCHA, embedded YouTube …) use click_iframe (selector resolves to the iframe element, the click lands inside) or click_at with raw coordinates.
  • Dialog handling. Native alert / confirm / prompt block page JS until handled. Use click_and_accept_dialog to do both in one call, or handle_dialog to dismiss an already-open one.
  • Ephemeral session. Each tool call opens a fresh WebSocket and closes it on return. That keeps the server stateless but means CDP event subscriptions are scoped to a single call (this is fine for the supplied tools — the dialog tool handles its own subscription internally).

⚠️ AI gets full browser control. Once connected, an AI client can drive any tab on the target browser: navigate, click, fill forms, run JS, read page content, take screenshots. Only point this server at browsers you are willing to give the AI full access to. Review tool calls in your MCP client.

License

MIT