Skip to main content
Glama

chrome-agent-mcp

Playwright MCP over a Chrome window you stay logged into, that does not steal your focus when the agent opens a tab.

You keep working in your own browser on one screen; the agent drives and you watch in another window, already logged into the sites it needs.

Install

Two paths, both exercised end to end on macOS with npm 11.17 (2026-11-07).

No install, via npx — nothing to keep updated, the MCP fetches the repo:

{
  "mcpServers": {
    "playwright": { "command": "npx", "args": ["-y", "github:patternlover/chrome-agent-mcp"] }
  }
}

As a project dependency, when you want it pinned:

npm i github:patternlover/chrome-agent-mcp
{
  "mcpServers": {
    "playwright": { "command": "chrome-agent-mcp" }
  }
}

npm i -g patternlover/chrome-agent-mcp is not verified: on this machine npm 11 fails with spawn sh ENOENT when a git spec is installed globally with a custom prefix. Use one of the two above, or install globally where npm's prefix is writable and check that chrome-agent-mcp status prints the patch line.

Then, once, start the browser it will drive:

chrome-agent-mcp open      # starts Chrome detached, not in the foreground
chrome-agent-mcp status    # port 9223 open, which browser, which profile

Log into whatever the agent needs in that window (its profile is persistent: ~/.local/share/chrome-agent-mcp/profile on macOS, %LOCALAPPDATA%\chrome-agent-mcp\profile on Windows). It survives restarts.

Related MCP server: stealth-browser-mcp

Why this exists

Two Playwright calls bring the browser's tab to the foreground, and on macOS that activates the application: your keystrokes stop landing where you were typing. Measured on macOS 2026-11-07, frontmost app before/after each step, through the MCP itself:

step

frontmost

initialize

unchanged

browser_tabs new

unchanged

browser_navigate

unchanged

browser_tabs select (the bringToFront path)

unchanged

browser_click, browser_evaluate, browser_type, browser_snapshot, browser_take_screenshot

unchanged

window.open(...) from a page

Chrome, for about a second

and, without the patches:

step

frontmost

newPage()

Chrome

page.bringToFront()

Chrome

Target.activateTarget

Chrome

The one step that still raises the browser is a popup the page opens itself (target=_blank, an OAuth sign-in window): that tab is created by Chrome, not by Playwright, so no client-side patch can make it background. It is transient — macOS gives the focus back — and it is avoided by navigating in the same tab instead of opening a window.

Upstream tried twice (microsoft/playwright#41430 merged then reverted by #41734; createPagesInBackground #41282 closed unmerged), so the fix has to be carried here. This package patches exactly two call sites in the bundled playwright-core/lib/coreBundle.js:

- { url: "about:blank", browserContextId: this._browserContextId }
+ { url: "about:blank", browserContextId: this._browserContextId, background: true }

- await this._mainFrameSession._client.send("Page.bringToFront");
+ /* chrome-agent-mcp: bringToFront disattivato, su macOS attiva la finestra */

The second one is not cosmetic: Page.bringToFront, Target.activateTarget and Chromium's ActivateContents all end up activating the window, so switching tab always costs the focus. Disabling it is what makes browser_tabs select safe, and it has a visible consequence: the window no longer follows the agent. The agent works on whatever tab it selected, the window keeps showing the tab you last clicked. To see what it has open, ask it to run chrome-agent-mcp tabs.

Both patches are idempotent and applied on every start, not only at install: npm 11 skips install scripts unless they are allowed, and on a git install the dependency is not there yet when the script runs. The install step only reports; the run-time check is the gate — if the patch cannot be applied, the MCP refuses to start instead of quietly stealing your focus. Both patches are applied all or nothing, so a half-patched bundle is never left behind.

Commands

command

what it does

chrome-agent-mcp

runs the MCP server (stdio), attached to the local Chrome

chrome-agent-mcp open

starts Chrome with the debug port, without bringing it to the foreground

chrome-agent-mcp close

quits that Chrome; the profile keeps its logins, the port closes

chrome-agent-mcp status

prints whether the port answers, the browser, the profile

chrome-agent-mcp tab <url>

opens a tab in the background, prints its target id

chrome-agent-mcp tabs

lists the open pages (id, title, url)

chrome-agent-mcp help

usage

Flags after the command go to playwright-mcp untouched: chrome-agent-mcp --caps=vision.

Environment: CHROME_AGENT_MCP_PORT (default 9223), CHROME_PATH (Chrome binary).

Limits

  • Popups still activate Chrome for about a second (see the table above).

  • The window does not follow the agent. Disabling bringToFront is what keeps the focus: a tab switch activates the app on macOS. Watch the tab you clicked, ask the agent for chrome-agent-mcp tabs to know what it has open.

  • macOS and Windows only. Linux is refused rather than guessed. Windows is unit-tested, not exercised on a real machine.

  • Google Chrome and Chrome for Testing, like @playwright/mcp itself. Arc, Stedding and other Chromium forks are unsupported: the debug port may work, nothing is guaranteed.

  • No extension tooling. For install/reload/inspect of extensions use chrome-devtools-mcp, which attaches to Chrome but not to Electron or unsupported forks.

  • The browser is started with --disable-background-timer-throttling, --disable-backgrounding-occluded-windows, --disable-renderer-backgrounding: without them a background tab throttles its timers and GTM / dataLayer measurements come out late.

  • The profile is a real Chrome profile with real cookies: see Security below.

Security

The Chrome DevTools port has no authentication. Chrome says so in their own note on remote debugging: while the port is open, any process of the same user can list the tabs and read the profile's cookies through the protocol. There is no flag for a password or a token, and none can be added by configuration — a token in front of the port would gate your client, not the port.

So the port is treated as a session, not as a service: open it when the agent has work to do, close it after.

chrome-agent-mcp open     # while working
chrome-agent-mcp close    # when done: Chrome quits, logins stay in the profile

The alternatives, when this is not enough: Playwright can launch the browser itself with --remote-debugging-pipe, which removes the port entirely (CDP travels on file descriptors 3 and 4; measured: zero listening sockets, no DevToolsActivePort), at the cost of one focus event at launch and a browser whose lifetime is the MCP session. The Playwright Extension takes the other route — no port, token per profile, per-client tab groups — but its background mode is not in the published MCP yet.

Development

npm test          # node --test: patcher (applies both, idempotent, completes a half-patched
                  # bundle, refuses a stale anchor leaving the file untouched), launcher, CLI, tabs

The patcher is tested against a fixture, so the suite runs without Playwright installed.

Upgrading the pin

@playwright/mcp pins a playwright-core version and the two anchors are tied to it. On a bump: npm i, then npm test, then node scripts/postinstall.mjs — a stale anchor fails loudly and names the patch that needs re-anchoring.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    Gives an AI assistant a persistent, stealth-configured Chrome browser that stays logged in across sessions, supports interactive first login, and can autofill credentials from the macOS Keychain and replay WebAuthn passkeys for sites that block scripted login.
    16
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    Enables agents to reuse a human-completed Chrome login session to open confirmed origins, read visible page text, and perform single click, fill, or key press actions without ever handling passwords or exposing cookies.
    6
    MIT