Skip to content

Getting started

Get monkbrowse driving your real Chrome — one profile first, then many.

Prerequisites

  • Node (for npx) — or Bun / pnpm if you prefer bunx / pnpm dlx
  • Chrome (or any Chromium browser with MV3 + offscreen support)
  • An MCP client: Claude, Cursor, VS Code (agent mode), Windsurf, or the MCP Inspector

1. Add the server to your MCP client

The server is on npm, so your client just runs it — nothing to download or build:

jsonc
{
  "mcpServers": {
    "monkbrowse": { "command": "npx", "args": ["-y", "monkbrowse"] }
  }
}

One-click buttons and the exact spot each client keeps this are on the Install page. Options (rarely needed): --control-port <n> (default 9219) moves the session control port, and --allow-extension <id...> allow-lists extra extension ids (needed for unpacked/dev builds — see below). --port <n> exists for tests only: the extension always dials 127.0.0.1:9222, so moving the server's port without rebuilding the extension just breaks the connection.

2. Install the extension in your first profile

Install monkbrowse from the Chrome Web Store (one click, auto-updates). Then:

  1. Click the monkbrowse toolbar icon — the popup opens.
  2. That's it — the extension connects to the local server (127.0.0.1:9222) on its own; there is nothing to configure. Optionally set a Name (e.g. Work) in Settings; the AI addresses the profile by the slug derived from it (work). No name set → one is derived from the profile's signed-in account, or the server assigns chrome-1, chrome-2, ….
  3. The status reads Connected once it reaches a running server.

Each Chrome profile is its own world, so install the extension in each profile you want the AI to reach.

Running an unpacked/dev build? Nothing to configure. The manifest pins a key, so every unpacked build of this repo gets the id ihmmmpgoddmkefjpenoiilcfgipnmggp, which the server allow-lists alongside the Web Store id. Only a fork with its own key needs --allow-extension <id>.

A server must be running for it to connect. The extension alone connects to nothing. Your MCP client starts the server when it launches — but to check the connection on its own, run the doctor (next).

Quick check — is the extension connecting?

Run the doctor. You do not have to quit your AI app: if a monkbrowse server already owns the extension port, the doctor attaches to it over the control port and reports what that server sees. If nothing owns the port, it binds the port itself and reports directly.

bash
npx -y monkbrowse doctor                                # installed from npm
npx -y monkbrowse doctor --probe                        # also read the shared tab
bun run doctor                                          # from a clone
npx -y monkbrowse doctor --allow-extension <id>         # a fork with its own key

Load the extension, and you should see:

  [time] connected profiles:
      ✓ Work  ·  profile "work"  ·  12 tabs

If instead the extension is being refused, the doctor says so and prints the exact flag that admits it — this is by far the most common cause of "it just won't connect" with an unpacked build:

  ✗ 4 connection attempts REFUSED — the extension is not on the allow-list:
      chrome-extension://lkpfocmepjhemnadbjedplnemafeabif  ×4

    THIS IS WHY NOTHING CONNECTS.

    A monkbrowse build (Web Store or `bun run build` + Load unpacked) is trusted
    automatically, so this one is from elsewhere: a build predating the pinned
    manifest key, a fork, or a copy with its own key. Admit it explicitly.
    ...

With --probe it goes one step further and reads the active shared tab once, printing its title, URL, and element count — that proves the whole chain, not just the handshake:

      ↳ read active tab: "Hacker News" (https://news.ycombinator.com) — 84 elements found

If you see that, the browser half works — any remaining issue is on the MCP side (server not launched by your client, or a tool call). If you see neither a profile nor a refusal, nothing is reaching the port at all: open the extension's offscreen console (Step "Troubleshooting" below) to see why. Ctrl-C stops the doctor; if it bound the port itself, stop it before starting your MCP client.

Then, with your MCP client running, ask your AI to run browser_list_tabs.

Share the tabs the AI may use

By default the AI sees nothing. In the popup, each tab has a Share toggle — flip on the tabs you want the AI to control. Only shared tabs get a number (1, 2, 3…) and appear in browser_list_tabs; the rest stay private. Unshared tabs (banking, email, whatever) are invisible to the AI, and a tool call against one is refused.

So the flow is: share a tab → it gets a number → tell your AI "on tab 2, …".

4. Add more profiles

Chrome runs each profile as its own world, so the extension is installed per profile:

  1. Switch to another Chrome profile (or create one).
  2. Install the same extension there (Web Store — or Load unpacked for a dev build).
  3. Optionally give it a Name in Settings (e.g. Personal). It connects to the same server on its own.

The single server now sees both — every profile shares port 9222, and each is identified by its own profileId (a stable uuid the extension announces). browser_list_tabs aggregates every profile, with each tab shown as a simple number (1, 2, 3…) — the same number in that profile's popup. Address a tab as { profile, tab }; address a profile by its slug (personal), a unique prefix, or its profileId — or omit profile to use the focused one.

Profiles never conflict: a reconnecting profile only ever replaces its own old socket, and a new profile never kicks another off (up to 32 at once).

5. Verify it works

Ask the AI (or use the MCP Inspector: bun run --cwd apps/server inspector):

  • browser_list_tabs → tabs from every connected profile, each shown as Label — profile "slug" (id-prefix)
  • browser_navigate { profile: "work", url: "https://example.com" } → drives that profile
  • browser_snapshot { profile: "personal" } → reads the other profile's active tab

Troubleshooting

SymptomCause / fix
"No browser profile is connected"The extension isn't connected. Open its popup — the status dot should be green Connected; if not, check your MCP client is running (it launches the server). Run npx -y monkbrowse doctor to see which half is at fault — you can leave the client running.
Doctor says it "could not ask" the process on :9222Whatever holds :9222 is not a monkbrowse server (often a chrome --remote-debugging-port or a VM port forward). Identify it with lsof -nP -iTCP:9222 -sTCP:LISTEN, or move monkbrowse with --port.
Unpacked build never connectsA current build of this repo is allow-listed by default, so this is an older build (predating the pinned manifest key) or a fork with its own. Rebuild, or run npx -y monkbrowse doctor — it names the id and prints the --allow-extension flag to add to your MCP config.
Popup says "update the extension" / "update the server"Version mismatch across the wire (protocol check). Update the named side — npx monkbrowse@latest for the server, Web Store auto-update (or rebuild) for the extension.
Tool hangs then times outThe target tab is a chrome:// / Web Store page (Chrome blocks scripting there), or the service worker was asleep — retry; it reconnects.
Badge flips on/offNormal MV3 service-worker cycling; the offscreen socket + alarm reconnect keep it alive. Persistent flapping → check a server is running.
Snapshot looks sparseThe accessibility walker surfaces interactive/structural elements; very custom widgets may under-report. Capture a fresh snapshot before acting on a ref.

What's where

Apache-2.0 licensed. Privacy