open-browser-mcp
v1.0.1
Published
MCP server that connects AI agents to your real Chrome browser — cookies, sessions, extensions and all
Maintainers
Readme
Open Browser MCP
MCP server that connects AI agents to your real Chrome browser — your actual profile with cookies, login sessions, extensions, and bookmarks. No isolated profiles, no Puppeteer, no Playwright.
Why this exists
Every other browser automation tool launches a sandboxed browser. That means no logged-in sessions, no cookies, no extensions. Open Browser MCP uses your real Chrome via a lightweight extension + CDP, so the agent works in the same browser context you do.
Architecture
MCP Client (Claude Code, Cursor, Windsurf, etc.)
| stdio
MCP Server (Node.js)
| WebSocket (localhost:9877)
Chrome Extension (Manifest V3)
| chrome.debugger CDP + content scripts
Your Real BrowserThe MCP server communicates with your editor via stdio (the standard MCP transport). A WebSocket bridge connects to a Chrome extension that uses chrome.debugger (CDP) for input events, network capture, screenshots, and more. Content scripts handle DOM reading and provide a fallback when CDP is unavailable.
Quick start
1. Install the MCP server
npm install -g open-browser-mcp2. Install the Chrome extension
Option A: Chrome Web Store (recommended)
Install from the Chrome Web Store listing — one click, automatic updates.
Option B: Manual install (Developer mode)
- Download or clone this repository
- Open
chrome://extensionsin Chrome - Enable Developer mode (toggle in the top right)
- Click Load unpacked
- Select the
extension/folder from this project
Manual installs do not auto-update. Pull the latest version and reload the extension to update.
3. Configure your MCP client
Add the server to your MCP client's configuration. The server uses stdio transport — it reads from stdin and writes to stdout, which is the standard MCP communication method.
Add to .claude/settings.json (project) or ~/.claude/settings.json (global):
{
"mcpServers": {
"browser": {
"command": "open-browser-mcp"
}
}
}Or use the CLI:
claude mcp add --transport stdio --scope user browser -- open-browser-mcpAdd to ~/.cursor/mcp.json (global) or .cursor/mcp.json (project):
{
"mcpServers": {
"browser": {
"command": "open-browser-mcp"
}
}
}Restart Cursor after editing.
Add to ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"browser": {
"command": "open-browser-mcp"
}
}
}On Windows the path is %USERPROFILE%\.codeium\windsurf\mcp_config.json. You can also access it via Settings > Tools > Windsurf Settings > View Raw Config.
Add to ~/.codex/config.toml:
[mcp_servers.browser]
command = "open-browser-mcp"
args = []Codex uses TOML format with
mcp_servers(underscore). Stdio transport only.
Add to opencode.json (project root) or ~/.config/opencode/opencode.json (global):
{
"mcp": {
"browser": {
"type": "local",
"command": ["open-browser-mcp"],
"enabled": true
}
}
}OpenCode uses
mcp(notmcpServers), andcommandis an array.
Add to ~/.omp/mcp.json (global) or .omp/mcp.json (project):
{
"mcpServers": {
"browser": {
"command": "open-browser-mcp"
}
}
}Pi also auto-discovers MCP configs from Claude Code, Cursor, and Windsurf.
Any MCP client that supports stdio transport can use this server. The general pattern is:
{
"mcpServers": {
"browser": {
"command": "open-browser-mcp"
}
}
}If running from source instead of a global npm install:
{
"mcpServers": {
"browser": {
"command": "node",
"args": ["/path/to/open-browser-mcp/server/index.js"]
}
}
}4. Use it
Start your MCP client and try:
> Create a browser session and navigate to github.com
> Take a screenshot of the current page
> Click the sign-in button
> Fill in the username field with "myuser" and press EnterThe agent calls browser_create_session first (required), then uses the 58 available tools to interact with your browser.
Tools (58)
Organized by category. See docs/tools-reference.md for full parameter details.
Navigation
| Tool | Description |
|------|-------------|
| browser_create_session | Required first step. Creates the "Open Browser" tab group and attaches CDP |
| browser_navigate | Navigate to a URL. External domains prompt for user approval |
| browser_close | Close a tab (defaults to active tab) |
| browser_go_back | Go back in browser history |
| browser_go_forward | Go forward in browser history |
Input & Interaction
| Tool | Description |
|------|-------------|
| browser_click | Click an element by @eN ref. Supports right-click and double-click |
| browser_type | Type text into an input field. Use slowly:true for autocomplete fields |
| browser_hover | Hover over an element to trigger hover states |
| browser_drag | Drag one element to another |
| browser_select_option | Select a dropdown option by value or visible text |
| browser_press_key | Send keyboard events (Enter, Tab, Ctrl+A, etc.) |
| browser_file_upload | Upload files to a file input element |
Reading & Inspection
| Tool | Description |
|------|-------------|
| browser_snapshot | Get all interactive elements with @eN refs, roles, and text. Primary inspection tool |
| browser_read_page | Read full page as text or HTML with pagination |
| browser_read_markdown | Convert page to clean markdown with boilerplate removed |
| browser_find | Search by CSS selector or text. Returns up to 20 matches |
| browser_javascript | Execute JavaScript on the page |
| browser_read_console | Read captured console messages (log, warn, error) |
Verification
| Tool | Description |
|------|-------------|
| browser_verify_element_visible | Assert an element is visible (PASS/FAIL) |
| browser_verify_text_visible | Assert text exists on the page (PASS/FAIL) |
| browser_verify_list_visible | Assert all items in a list are visible (per-item PASS/FAIL) |
| browser_verify_value | Assert an element has a specific value (PASS/FAIL) |
Mouse & Coordinates
| Tool | Description |
|------|-------------|
| browser_mouse_click_xy | Click at exact pixel coordinates. Use humanLike:true for captchas |
| browser_mouse_move_xy | Move mouse to coordinates with optional Bezier movement |
| browser_mouse_drag_xy | Drag between two coordinate positions |
Tabs
| Tool | Description |
|------|-------------|
| browser_tab_list | List all tabs in the session group |
| browser_tab_switch | Switch to a tab by ID |
| browser_tab_create | Create a new tab (optional URL) |
Screenshots & Media
| Tool | Description |
|------|-------------|
| browser_screenshot | Capture screenshot (viewport, full page, or clipped region) |
| browser_pdf_save | Save page as PDF |
| browser_captcha_screenshot | Focused screenshot of captcha widget area |
| browser_resize | Resize the browser window |
Captcha
| Tool | Description |
|------|-------------|
| browser_solve_captcha | Detect and click captcha checkbox (Turnstile, reCAPTCHA, hCaptcha) |
| browser_captcha_tiles | Analyze reCAPTCHA tile challenge grid with @tN refs |
| browser_batch_click | Click multiple elements/coordinates in sequence |
Batch Operations
| Tool | Description |
|------|-------------|
| browser_batch | Execute multiple actions in one call (click, type, select, key, wait, scroll) |
Network & Storage
| Tool | Description |
|------|-------------|
| browser_network_requests | Read captured network requests (method, status, URL, timing) |
| browser_get_cookies | Read cookies for current page or specific URLs |
| browser_set_cookie | Set a cookie with name, value, domain, and flags |
| browser_clear_storage | Clear localStorage, sessionStorage, and/or cookies |
| browser_block_urls | Block URL patterns from loading (ads, trackers, etc.) |
Device Emulation
| Tool | Description |
|------|-------------|
| browser_emulate_device | Emulate mobile/tablet viewport, user agent, and network conditions |
| browser_set_geolocation | Override GPS coordinates |
DevTools & Performance
| Tool | Description |
|------|-------------|
| browser_get_accessibility_tree | Get the computed accessibility tree (roles, names, values) |
| browser_start_tracing | Start a Chrome performance trace |
| browser_stop_tracing | Stop trace and return results |
| browser_generate_locator | Generate CSS, XPath, and aria locators for an element |
| browser_memory_snapshot | Get JS heap size, DOM node count, layout metrics |
| browser_audit_accessibility | Run an accessibility audit (ARIA, contrast, labels) |
Timing & Waiting
| Tool | Description |
|------|-------------|
| browser_wait | Wait for time (ms) or CSS selector to appear |
| browser_wait_for_text | Poll until specific text appears on the page |
| browser_scroll | Scroll the page or scroll an element into view |
Script Injection
| Tool | Description |
|------|-------------|
| browser_inject_script | Inject JS that runs before every page load (persists across navigations) |
Dialogs
| Tool | Description |
|------|-------------|
| browser_handle_dialog | Handle JavaScript alert/confirm/prompt dialogs |
Screen Recording
| Tool | Description |
|------|-------------|
| browser_screencast_start | Start recording as PNG frames at a given interval |
| browser_screencast_stop | Stop recording and save frames to disk |
Domain Permissions
| Tool | Description |
|------|-------------|
| browser_set_domain_mode | Set permission mode (approval, allow_all, strict) |
| browser_manage_domains | Add/remove domains from allowlist or blocklist |
Domain permission system
When the agent navigates to an external domain for the first time, a permission dialog appears in your browser. You choose how to handle it:
| Option | Behavior |
|--------|----------|
| This Session | Temporary approval — gone when Chrome closes |
| This Project | Saved to {cwd}/.open-browser-mcp/domains.json |
| All Projects | Saved to ~/.open-browser-mcp/domains.json |
| Block | Reject the navigation |
Localhost URLs are always allowed without prompting.
Permission modes
Set via browser_set_domain_mode:
| Mode | Behavior |
|------|----------|
| approval (default) | Popup for each new domain |
| allow_all | No domain checks |
| strict | Only allowlisted domains, no popups, everything else blocked |
Pre-approving domains
Use browser_manage_domains to pre-approve domains so no popup appears:
> Pre-approve github.com and stackoverflow.com for this projectThe agent calls browser_manage_domains with action:"allow" and domains:["github.com","stackoverflow.com"].
Visual indicator
Agent-controlled tabs show a pulsing pink border so you always know which tab the AI is operating on. The border appears when a session is created and disappears when it closes.
Configuration
Environment variables
| Variable | Default | Description |
|----------|---------|-------------|
| STATIC_PORT | 9876 | Port for the built-in test page server |
| WS_PORT | 9877 | WebSocket bridge port (must match the extension) |
Runtime files
The server creates a .open-browser-mcp/ directory in your working directory for:
| Path | Purpose |
|------|---------|
| .open-browser-mcp/domains.json | Project-level domain permissions |
| .open-browser-mcp/*.png | Saved screenshots |
| .open-browser-mcp/screencasts/ | Screencast frame recordings |
Global domain config is stored at ~/.open-browser-mcp/domains.json.
Add
.open-browser-mcp/to your.gitignore.
Requirements
- Node.js >= 18
- Chrome (any recent version)
- MCP client — Claude Code, Cursor, Windsurf, Codex, OpenCode, Pi, or any stdio-compatible MCP client
Running from source
git clone https://github.com/samonjoat/open-browser-mcp.git
cd open-browser-mcp
npm installThen point your MCP client to the local server:
{
"mcpServers": {
"browser": {
"command": "node",
"args": ["C:/path/to/open-browser-mcp/server/index.js"]
}
}
}Troubleshooting
Extension not connected
- Verify the extension is loaded and enabled at
chrome://extensions - Check that the extension's service worker is active (click "Service Worker" link on the extension card)
- Ensure port 9877 is not in use by another process
- The extension connects to
ws://127.0.0.1:9877— firewall or antivirus may block local WebSocket connections
"Debugger is already attached"
Another DevTools session or extension is using chrome.debugger on the same tab. Close other debugger connections and retry browser_create_session.
Port conflicts
If ports 9876 or 9877 are in use, set custom ports via environment variables:
STATIC_PORT=9880 WS_PORT=9881 open-browser-mcpThe extension's WebSocket URL is hardcoded to ws://127.0.0.1:9877. If you change WS_PORT, you must also update the extension's background.js to match.
Tools return "Not connected to Chrome extension"
The MCP server starts but the extension hasn't connected yet. Open Chrome with the extension loaded — the extension auto-connects on startup with exponential backoff retry.
Session idle after closing tabs
If you close all tabs in the "Open Browser" group, the session becomes idle. Call browser_create_session again to start a new session.
License
MIT
