Skip to main content
Glama
lldartsll

browser-for-claude

by lldartsll
README.md
<p align="center">
  <img src="assets/banner.png" alt="browser-for-claude banner" width="100%">
</p>

<h1 align="center">
  <img src="assets/logo.png" alt="browser-for-claude logo" width="32" valign="middle">
  browser-for-claude
</h1>

An [MCP](https://modelcontextprotocol.io) server that gives Claude control of a real, headed Chromium browser via [Playwright](https://playwright.dev). It exposes a small set of tools — navigate, click, type, read text, screenshot, run JS, get URL, close — so Claude can drive a live browser session instead of just reading static content.

## Features

- **Isolated from your real browser** — Claude never touches your everyday Chrome. See [Privacy & Isolation](#privacy--isolation) below.
- **Headed Chromium** — the browser window is visible, not run in the background, so you can watch what Claude does in real time.
- **Persistent session** — the same browser/page stays open across tool calls until explicitly closed, so multi-step flows (navigate → click → type → screenshot) act on one continuous session.
- **Minimal surface** — eight tools, each a thin wrapper over one Playwright action.

## Privacy & Isolation

This is **not** your everyday Chrome — it's a completely separate, throwaway browser instance:

- **Different binary.** Playwright launches its own bundled Chromium (installed via `npx playwright install chromium`), not the Chrome app on your machine.
- **No shared profile.** Each session starts from `browser.newContext()` — a brand-new, blank browsing context. It does not read your Chrome profile directory, so there's no access to your bookmarks, saved passwords, browsing history, extensions, or cookies.
- **No Google account.** Because the context starts blank, any site you're logged into in your real browser (Google, GitHub, etc.) shows up **logged out** here — Claude has no way to see or use your existing sessions.
- **Nothing persists across restarts.** `browser_close` (or the process exiting) discards the context entirely; nothing is written back to disk for next time.

In short: Claude can look at and click around a real, live web page, but it's working in its own sandboxed browser with a clean slate — never your personal one.

## Tools

| Tool | Description |
| --- | --- |
| `browser_navigate` | Navigate the headed Chromium window to a URL |
| `browser_click` | Click an element matching a CSS selector |
| `browser_type` | Fill a text input matching a CSS selector |
| `browser_get_text` | Read the text content of an element matching a CSS selector |
| `browser_screenshot` | Capture a PNG screenshot of the current page |
| `browser_evaluate` | Evaluate a JavaScript expression in the page context and return the result |
| `browser_get_url` | Return the current page URL |
| `browser_close` | Close the Chromium window and end the session |

## Requirements

- Node.js 20+
- npm

## Setup

```bash
npm install
npx playwright install chromium
npm run build
```

## Usage

### Standalone

```bash
npm start
```

This starts the MCP server on stdio (`dist/server.js`). It's meant to be launched by an MCP client, not run interactively on its own.

### With Claude Code

Add it as an MCP server, e.g. via a `.mcp.json` in your project:

```json
{
  "mcpServers": {
    "browser-for-claude": {
      "command": "node",
      "args": ["dist/server.js"]
    }
  }
}
```

Claude Code will then discover the `browser_*` tools automatically.

## Development

```bash
npm run build       # compile TypeScript (src -> dist)
npm run smoke-test   # launch a real browser and exercise every tool against example.com
```

The smoke test (`test/smoke-test.ts`) is an end-to-end check: it navigates to a real page, reads text, evaluates JS, takes a screenshot, and confirms that clicking a missing selector throws — all against a live Chromium instance rather than mocks.

## Project structure

```text
src/
  server.ts             MCP server: registers the browser_* tools
  browserController.ts  Playwright session management (launch/navigate/click/type/...)
test/
  smoke-test.ts         End-to-end smoke test against example.com
```

## How it works

`browserController.ts` lazily launches a single headed Chromium browser, context, and page on first use, and keeps reusing them across tool calls until `browser_close` is called. A launch guard (`launchInFlight`) ensures concurrent tool calls can't race into launching two separate browser instances.

## Caveats

- Only one browser session is supported at a time (no multi-tab/multi-context support).
- The isolation described above (see [Privacy & Isolation](#privacy--isolation)) cuts both ways: if a task genuinely needs an already-logged-in site, you'll need to log in manually within the session first — there's no way to reuse credentials from your regular browser.
- Intended for local/trusted use — `browser_evaluate` runs arbitrary JavaScript in the page with no sandboxing beyond what the browser itself provides.

## License

No license specified.

TDQS

A3.7/5.0

Scored across 8 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: navigating, clicking, typing, reading text, evaluating JS, taking screenshots, getting the URL, and closing the browser. There is no ambiguity or overlap.

Naming Consistency5/5

All tools share the 'browser_' prefix and follow a consistent verb-based pattern (navigate, click, type, get_text, evaluate, get_url, close). 'browser_screenshot' is the only deviation but still reads as an action.

Tool Count5/5

With 8 tools, the set is appropriately scoped for browser automation, covering session management, navigation, interaction, inspection, and evaluation. Each tool earns its place.

Completeness4/5

The set covers core browser workflows, but lacks explicit back/forward/refresh or wait commands. However, browser_evaluate can compensate for these missing operations, making gaps minor.