MCP Browser Extension

Quickstart

Register the MCP server, load the extension, and pair it. Three steps, one paste.

Up and running in one paste

Hand this to your AI agent (Claude Code, Cursor, Windsurf, anything MCP) and it installs the server, wires it into the client, and walks you through the two steps that must happen inside Chrome:

Set up MCP Browser Extension on this machine by fetching and following
https://raw.githubusercontent.com/Mehmoodqureshi/chrome-mcp/main/SETUP.md
exactly, step by step. Work autonomously and verify each step.

Prefer to read before you run an agent on your machine? SETUP.md is the exact file the agent follows. The manual steps are below.

1. Register the MCP server with your host.

Claude Code (terminal) — one command, no config file to find

claude mcp add chrome-mcp -s user -- \
  npx -y @mehmoodqureshi/chrome-mcp@latest \
  --allow-domain example.com --enable-mutations --persist-token

Everything before -- belongs to Claude Code; everything after it is this server's command and flags. Keep the -- or --allow-domain gets read as a Claude Code option.

-s user registers it for every project on your machine. Use -s local (the default) for just the current project, or -s project to write a .mcp.json your team can commit.

Check it came up with claude mcp list. After upgrading the server, reconnect it with /mcp inside a session — no restart needed.

Claude Desktop and other MCP hosts — JSON config

{
  "mcpServers": {
    "chrome-mcp": {
      "command": "npx",
      "args": ["-y", "@mehmoodqureshi/chrome-mcp@latest",
               "--allow-domain", "example.com", "--enable-mutations",
               "--persist-token"]
    }
  }
}

VS Code (GitHub Copilot) — .vscode/mcp.json

VS Code uses a top-level servers key, not mcpServers. Put this in .vscode/mcp.json for one project, or in your user mcp.json (MCP: Open User Configuration) for every project:

{
  "servers": {
    "chrome-mcp": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@mehmoodqureshi/chrome-mcp",
               "--allow-domain", "example.com", "--enable-mutations",
               "--persist-token"]
    }
  }
}

Run the tools from the Chat view with Agent selected. The full walkthrough is in VS Code Copilot browser MCP.

By default everything is deny-all (no domains, no eval, no mutations). Grant exactly what you need with --allow-domain <glob> (repeatable), --enable-mutations, --enable-downloads, --enable-uploads, --unsafe-enable-eval, or --unsafe-all-domains.

--enable-uploads permits upload_file (setting local file(s) on a page's file <input>). It is off by default because sending local files to a page is an exfiltration risk; it is also gated by the destination-domain allowlist. Pair it with --uploads-dir <path> to restrict uploads to files inside that directory (.. traversal is blocked) — strongly recommended for unattended use.

Pair once, never again. Both examples above include --persist-token, which is what makes the pairing survive a restart — drop it if you'd rather have the stricter default described next.

Without --persist-token a fresh token is minted every boot (the secure default), which means re-pairing the extension on each restart. With it, the token is stored 0600 at ~/.chrome-mcp/token and reused; the extension's keepalive auto-reconnects with no manual step. CHROME_MCP_TOKEN pins the token explicitly (and is never written to disk).

2. Install the extension — required; the server can drive nothing without it.

Install MCP Browser Extension from the Chrome Web Store. One click, no Developer mode, and Chrome keeps it updated for you. This is the way to install it.

3. Click Connect. A fresh install opens the extension's Settings with a Connect button (it is in the toolbar popup too). Click it, allow the one permission Chrome asks for, and you are paired: the server registers a small helper with Chrome every time it starts, and the button asks it for the port and token. Chrome lets only this extension talk to that helper. If the server ever changes its token, the extension fetches the new one by itself. Nothing to copy or paste.

Developers: load it unpacked instead

The extension also ships inside the npm package, and every time the server boots it copies it to ~/chrome-mcp-extension (%USERPROFILE%\chrome-mcp-extension on Windows; CHROME_MCP_EXTENSION_DIR moves it). chrome://extensions → enable Developer mode → Load unpacked → pick that folder. It pairs itself from a pairing.json the server writes there, and the server refreshes the files on each boot (never with an older build) so it reloads itself within 30 seconds.

An unpacked copy does not update through Chrome, so its popup suggests the store copy. Unpacked builds carry the store's public key and so have the same id: load one or the store copy in a Chrome profile, not both. Working from a git clone? npm install && npm run build:ext first; extension-dist/ is gitignored.

Where to see the badge: it sits on the extension's icon in Chrome's toolbar, not on the chrome://extensions page. Chrome hides new extensions behind the puzzle-piece button at the right of the address bar, so click that, find MCP Browser Extension, and click the pin next to it once; the icon then stays in the toolbar. Hover it for the status in words.

BadgeMeaning
green dotpaired and connected
yellow dotsconnecting
grey circlenot paired yet (no server has run, or no pairing file)
red exclamation marktoken rejected; the server rotated it, re-pairs by itself in a moment

Manual fallback (the helper is turned off with --no-native-host, or Connect reports a problem): run npx -y @mehmoodqureshi/chrome-mcp@latest --print-pairing, open the extension's Settings, and paste the port + token from ~/.chrome-mcp/handshake.json.

Running more than one session

Every MCP host session (each Claude terminal, tab or window) starts its own MCP Browser Extension server, and they all share your Chrome at once. The first one to start owns the bridge port and the extension connections — the hub. Each later session finds the port held by a live MCP Browser Extension server and joins it as a peer: its tool calls are relayed through the hub to the same browsers, so every session keeps working side by side. Nobody is disconnected.

When the hub's session ends, its peers race for the port; one takes it over (with the same token, so the extension re-pairs by itself within a few seconds) and the rest join the new hub. A call that was in flight at that moment fails once with EXTENSION_DISCONNECTED and is retried automatically when it is safe to repeat.

Peers authenticate with the pairing token from the 0600 handshake file, so only your own OS user can join. A server too old to share the port is replaced as before: it is verified to be an MCP Browser Extension server, then stopped. Anything that isn't a verified MCP Browser Extension server is never touched — a port held by some other program is reported, never killed.

Sessions share one browser, so they also share its tabs: two sessions driving the same tab at the same moment will step on each other. Give each session its own tabs (tab_new), or its own Chrome profile (below).

Each session can also drive several browsers at once: load the extension in each Chrome profile and they all pair to the same server, each under its own profile name. Tools act on the active profile — pick it with --profile <name> at startup or the profile_use tool at runtime.

Naming is automatic. Chrome won't tell an extension which profile it runs in, so each install keeps a random id and the server names it: the first browser is default, the next profile-2, then profile-3, and so on. Names are stored in ~/.chrome-mcp/profiles.json, so a browser keeps its name across restarts. chrome_status lists every paired browser (with its active tab as a hint), and profile_rename gives one a friendly name (profile-2 → work). To pin a name yourself instead, type it into the extension's Options → Profile; that always wins.

Without --port, each server binds an ephemeral port (no conflict ever), but the port changes every boot — so you'd re-pair the extension each time. Pin --port plus --persist-token for a pair-once setup.

Windows

WSL2 is not required — native Windows works. One config change is, though: on Windows npx is npx.cmd, a batch shim, and MCP hosts spawn the server without a shell, which cannot execute a .cmd. So "command": "npx" fails to start. Wrap it in cmd /c:

{
  "mcpServers": {
    "chrome-mcp": {
      "command": "cmd",
      "args": ["/c", "npx", "-y", "@mehmoodqureshi/chrome-mcp@latest",
               "--allow-domain", "example.com", "--enable-mutations",
               "--persist-token"]
    }
  }
}

Or from Claude Code: claude mcp add chrome-mcp -- cmd /c npx -y @mehmoodqureshi/chrome-mcp@latest --allow-domain example.com

Everything else is the same — load %USERPROFILE%\chrome-mcp-extension and pair as above.

On this page