Browser MCP by Agent360

MCP serverWeb & browsing

Drive your real, logged-in Chrome from any AI agent - 40 tools. Needs our Chrome extension too.

Unavailable. This server has no hosted endpoint yet, so ahel can't serve it.

Connect ahel once, and every AI you use reads what you have installed.

From the project's README

As published by Agent360dk/browser-mcp in README.md.

Your AI agent drives your real, logged-in Chrome - and works where headless tools die.

It is the browser you are already signed into. No login step to fail, no API key to wire up, no fresh profile that is a stranger to every account you have. Up to 20 agents at once, each in its own colour-coded tab group. 40 tools, MIT, runs on your machine.

What it can and cannot get past - every wall, marked measured, by design, not yet, or won't. Including the ones we have not fixed.

Watch the 37-second demo with sound →

Browser MCP gives Claude Code (and any MCP client - Cursor, VS Code agent mode) control of your actual Chrome: your cookies, your sessions, your 2FA. So it works on CAPTCHA, 2FA and anti-bot sites where Playwright and Puppeteer get blocked - because it's you browsing.

The killer move: it hits a login wall, reads the verification code from your own Gmail tab, and continues the sign-in. No API can do that. Operate platforms with no API, QA your own web app end-to-end, or work dashboards, LinkedIn and Reddit at human pace - with you approving the sensitive steps.

40 tools. Auto-clicks the reCAPTCHA v2 checkbox, with a human fallback for the rest. Multi-session color-coded tab groups. MIT, free, and it runs on your machine - no account, no telemetry, nothing sent to us.

The whole thing, in four steps

1 - Install the Chrome extension. One click from the Chrome Web Store; Chrome keeps it updated. No store? See the unpacked install below.

2 - Add the MCP server. Paste this in a terminal. Required - the extension does nothing on its own:

claude mcp add --scope user browser-mcp -- npx @agent360/browser-mcp@latest

3 - Restart Claude Code. That is what starts the server. The extension shows no badge until step 4 - the server only takes a port the first time your agent actually uses the browser. A green badge with the number of connected agents appears then; nothing on the icon before that is normal. (The icon itself never changes colour - it is the badge that turns green.)

4 - Say this, to check it worked. Paste it to Claude Code:

Take a screenshot of my current Chrome tab.

You get an image back instead of "I don't have browser access". That's it - you're running.What else to say

Using Cursor, VS Code, Codex or Windsurf? Same server, that client's own config - see browsermcp.dev/docs. Everything below is the long version.

The long version - install, step by step

Browser MCP is two halves and you need both: a Chrome extension (drives the browser) and a local MCP server (what your agent actually talks to). Installing only the extension - e.g. straight from the Chrome Web Store - leaves it stuck on "Not connected", because there is no server for it to reach. Chrome cannot install the server, and npm cannot install the extension. Hence two steps.

Step 1: Register the MCP server with Claude Code

claude mcp add --scope user browser-mcp -- npx @agent360/browser-mcp@latest

That is Claude Code's own MCP command, so the entry lands in the config Claude Code actually reads. --scope user makes it available in every project.

Want the extension files on disk for the unpacked install in Step 2? Also run:

npx @agent360/browser-mcp install

It copies the extension to ~/.browser-mcp/extension/ and prints that path in the terminal - copy it. (Use it for the extension files only; register the server with claude mcp add above.)

Step 2: Load the extension in Chrome

Chrome won't let extensions install themselves from npm - you load it manually one time. To update later, re-run the install command and reload it (see Keeping it updated). Prefer the Chrome Web Store install if you'd rather have the extension auto-update.

  1. Open Chrome and type chrome://extensions in the address bar
  2. Toggle "Developer mode" ON (top right corner)
  3. Click "Load unpacked" (top left, next to "Pack extension")
  4. Navigate to ~/.browser-mcp/extension/ and click "Select"
    • On Mac: Press Cmd+Shift+G in the file picker, paste ~/.browser-mcp/extension/, press Enter
    • On Windows: Paste %USERPROFILE%\.browser-mcp\extension\ in the address bar
    • On Linux: Type ~/.browser-mcp/extension/ in the path field
  5. Restart Claude Code so it picks up the new MCP server

That's it. The Browser MCP icon will appear in your toolbar, and 40 browser tools are now available in Claude Code.

Alternative: Manual zip download (no npm)

If you don't want to use npm, download the extension directly:

  1. Download the extension zip (agent360-browser-mcp-<version>.zip) from the latest GitHub release
  2. Unzip the file (anywhere - e.g. ~/Downloads/browser-mcp-extension/)
  3. Follow Step 2 above, but select the unzipped folder instead of ~/.browser-mcp/extension/
  4. Register the server - run claude mcp add --scope user browser-mcp -- npx @agent360/browser-mcp@latest, or add this to ~/.claude.json by hand:
    {
      "mcpServers": {
        "browser-mcp": {
          "command": "npx",
          "args": ["@agent360/browser-mcp@latest"]
        }
      }
    }
    

Chrome Web Store (no Developer mode, auto-updating extension)

This replaces Step 2 only - you still need Step 1.

  1. Install the extension from the Chrome Web Store → - no Developer mode toggle, and Chrome keeps it updated for you.
  2. Register the MCP server:
    claude mcp add --scope user browser-mcp -- npx @agent360/browser-mcp@latest
    
    (For Cursor / VS Code / Codex, use that client's own MCP config instead - see browsermcp.dev/docs.)
  3. Restart Claude Code.

Skip step 2 and the extension icon will sit on "Not connected" forever - that is the symptom of a missing MCP server, not a broken extension.

You're in. Now what?

Nothing happens until you ask, and the hardest part of a new tool is knowing what to ask for. Paste one of these to your agent:

Say thisWhat it shows
"Take a screenshot of my current Chrome tab."Start here. An image back instead of "I don't have browser access" means both halves are talking. That is the whole install test.
"Open my Gmail tab and tell me who sent my last 3 emails."The one that shows the difference - it works because it is your browser, already signed in. A headless tool hits a login wall here.
"Go to my analytics dashboard, pull this month's numbers, and put them in a table."Any dashboard you are already logged into. No API key, no export, no integration to build first.
"Fill in this signup form with my details. Stop and ask me before anything sensitive."You stay in the loop - it hands control back for passwords, payment details, or anything it should not decide alone.
"Log me in here. If it emails a code, read it from my Gmail tab and continue."The move no API can make: it reads the one-time code out of your own inbox and finishes the sign-in.
"Walk through my app's signup flow as a real user and tell me where it breaks."End-to-end QA of your own product, in the same browser your users have.

The pattern: anything you would do yourself in a browser, on a site you are already signed into. It is strongest where there is no API - internal dashboards, admin panels, portals, LinkedIn. Built something good? Add it to the gallery.

Why This Over Playwright MCP / BrowserMCP?

Browser MCPPlaywright MCPBrowserMCP.io
BrowserYour real Chrome, via extensionPersistent profile by default, or your Chrome via their extensionYour real Chrome
MaintainedActively - latest release v1.29.1 (2026-09-13)Actively (Microsoft)Last commit Apr 2025
Logins/cookiesYour existing sessionPersistent profile keeps logins between runsAlready authenticated
Several agents, one logged-in profile20 concurrent, each with its own color-coded tab groupTheir docs: concurrent clients on one profile conflict - each extra client needs --isolated or its own --user-data-dirSingle session
Human-in-the-loopbrowser_ask_user - 2FA, CAPTCHA, credential inputNoneNone
Provider integrations9 built-in (Stripe, HubSpot, Slack...)NoneNone
CORS bypassbrowser_fetch from extension backgroundN/ALimited
Network monitoringbrowser_wait_for_network via CDPBuilt-inNone
CSP-strict sitesChrome Debugger API throughoutWorks (headless)Limited
Custom dropdownsAngular Material, React Select supportWorks (headless)Limited
Installclaude mcp add + extension from the Chrome Web Storenpx @playwright/mcpManual clone

The pages that defeat everything else

The reason this works where headless dies is not that it slips past anything. It is that there is nothing to slip past: it is your Chrome, your session, your consent. What is left is the hard part - pages that fight any automation because of how they are built.

Every release is gated on a flow test against a real Chrome that has to survive exactly those: all 40 tools are exercised, and the gate also checks that the extension Chrome is running is the one being released - not another copy with the same version number. The failures that do show up are honest ones: mouse events are not delivered to a tab that is not in front, and the tools say so instead of reporting success. What the test covers

  • strict CSP - navigate, read, execute, wait and click all still work (falls back to the Chrome Debugger API when script injection is blocked)
  • cross-origin iframes - seen into and reached inside
  • shadow DOM - selectors reach through it
  • controlled inputs - fill sticks in a React-style controlled field
  • honesty checks - click refuses a 0×0 element instead of hitting (0,0), and says so when the page never took the event

Known limitation: working in a tab you are not looking at

In a tab you are not looking at, the agent can navigate, read, screenshot, run scripts, fill fields and click. Chrome does not deliver mouse and keyboard events to a tab that is not the visible one in its window, so key presses, hover, double-click, coordinate clicks and combobox typing fail with an error that says so, and the agent will then call browser_switch_tab, which brings that tab and its window in front of you.

Measured across 160 real sessions: that happens on roughly one call in forty, most often on Enter. Fully hands-off background work is planned for 1.30. Some of it cannot be solved at all: CSS :hover is a state the renderer owns and no script can fake it, a script-dispatched event is never isTrusted, elementFromPoint stops at a cross-origin iframe, and the text selection a real double-click makes is browser behaviour rather than an event.

That last group matters most. A tool that quietly reports success is worse than one that fails, because you build on the answer. Where we still fall short of it, it is written down: see #19.

Corrected 2026-09-07. This table used to say Playwright MCP was headless and made you log in every time. That was wrong, and it had been wrong for a while - Microsoft's own README documents a persistent profile as the default, plus a browser extension for using the Chrome you already have. The row that actually survives is the one above it, and it is their documented limitation, not our claim: "A persistent profile can only be used by one browser instance at a time, so concurrent MCP clients sharing the same workspace will conflict." If you run one agent, Playwright MCP will serve you well. The difference shows up when you run twenty against the same logged-in browser.

On the name: the similarly-named browsermcp.io (@browsermcp/mcp) is a different, unaffiliated project with no commits since April 2025. This is Browser MCP by Agent360 (@agent360/browser-mcp) - actively maintained. Full side-by-side →

Environment variables

Both are optional. Neither is needed for normal use.

VariableEffect
BROWSER_MCP_CHECK_NPM=1Makes browser_provide_feedback also compare this server against the latest version published on npm. Off by default, so the call stays fast and works offline.
BROWSER_MCP_EXTENSION_ID=<32-char id>Pins the server to one specific Chrome extension. Use it when more than one copy of Browser MCP is loaded and you want a given session to always talk to the same one.

40 Tools

Navigation & Content

ToolDescription
browser_navigateNavigate to URL (reuses tab, or new_tab=true)
browser_get_page_contentGet page text or HTML
browser_screenshotScreenshot via Chrome Debugger (works even when tab isn't focused)
browser_execute_scriptRun JavaScript in page context
browser_extract_listRead every row of a long/virtualised list by scrolling its container until no new rows appear

Interaction

ToolDescription
browser_clickClick via CSS or text selector (text=Submit, button:text(Next))
browser_fillFill input fields (works on CSP-strict sites)
browser_press_keyKeyboard events (Enter, Tab, Escape, modifiers)
browser_scrollScroll to element or by pixels
browser_waitWait for element to appear
browser_hoverHover for tooltips/dropdowns
browser_select_optionNative <select> + custom dropdowns (Angular Material, React Select)
browser_set_comboboxAutocomplete/combobox: type query → wait for filtered listbox → click option (multi-value chip support). Use when browser_select_option fails on lazy-rendered options
browser_set_dateRobust date inputs: tries native value-set → masked typing → calendar-picker navigation (MUI/AntD/react-datepicker/Lexical). Use when browser_fill fails on date fields
browser_dismiss_overlaysBulk-dismiss popups/modals/tooltips/banners via aria-label/text/×-char heuristics. non_critical mode preserves dialogs with form data
browser_handle_dialogAccept/dismiss native alert/confirm/prompt dialogs
browser_double_clickTrue double-click (two trusted press/release pairs)
browser_right_clickRight-click to open page-level context menus
browser_click_xyEscape hatch: click at raw viewport coordinates (CSS pixels) with trusted mouse events
browser_reattach_debuggerRecovery: force-detach and re-attach the Chrome debugger on the current tab

Tabs & Frames

ToolDescription
browser_list_tabsList session's tabs only
browser_switch_tabSwitch to tab by ID
browser_close_tabClose tab (session-owned only)
browser_get_new_tabGet most recently opened tab (OAuth popups)
browser_list_framesList iframes on page
browser_select_frameExecute JS in specific iframe

Data & Network

ToolDescription
browser_fetchHTTP request from extension (bypasses CORS)
browser_wait_for_networkWait for specific API call to complete
browser_extract_tokenNavigate to provider dashboard + extract API token

CAPTCHA Solving

ToolDescription
browser_solve_captchaDetect and solve CAPTCHAs. Auto-detects reCAPTCHA v2/v3, hCaptcha, Turnstile, FunCaptcha. Actions: detect, click_checkbox (auto-click, often passes when signed into Google), click_grid (AI vision guided), ask_human (fallback)

Human-in-the-Loop

ToolDescription
browser_ask_userShow overlay dialog for 2FA, CAPTCHA, credentials, or any user input

Data

ToolDescription
browser_get_cookiesGet cookies for a site this session has open
browser_set_cookiesSet cookies for a domain
browser_get_local_storageRead localStorage from page
browser_set_local_storageWrite localStorage values
browser_console_logsCapture console.log/warn/error messages from page
browser_upload_fileUpload files to <input type="file"> via Chrome Debugger API (no dialog)
browser_drop_fileUpload via drop-zones: finds hidden <input type="file"> in target subtree/parent (up to 2 levels). Use when browser_upload_file fails because the zone has no visible input

Diagnostics & feedback

ToolDescription
browser_provide_feedbackSelf-check + report in one call. Compares this server against the latest on npm, the connected extension against this server, and detects more than one Browser MCP extension connected at once - the three things that explain most "it just stopped working" moments. Returns a verdict (current / outdated / conflict / disconnected), concrete fix steps, and a pre-filled issue link for whatever is genuinely missing. Your agent calls it on its own whenever a tool blocks it
browser_aboutProject info + pre-filled links to submit a wish, use-case, or bug

Multi-Session Support

Each Claude Code conversation gets its own MCP server on a unique port (9876-9895). The Chrome extension connects to all active servers simultaneously.

Need more than 20 at once? The range is a setting, not a hard limit, but both halves have to agree. Set BROWSER_MCP_MAX_PORT in every chat's MCP config, set bmcpPorte to the same range in the extension's storage, then reload the extension: it reads the range only when it starts. Change only the server side and chat 21 binds a port the extension never looks at, so the browser goes quiet in that chat with nothing to explain it. 100 is plenty; the hard cap is 200. Every extra port costs your browser one refused connection every two seconds, whether you use it or not, so do not widen it for fun.

Claude Session 1 ←(stdio)→ MCP :9876 ←(WS)→
Claude Session 2 ←(stdio)→ MCP :9877 ←(WS)→  Chrome Extension → Browser
Claude Session 3 ←(stdio)→ MCP :9878 ←(WS)→
  • Session isolation - each session gets a color-coded Chrome Tab Group
  • Tab ownership - sessions can only see and control their own tabs
  • Auto-cleanup - processes exit when Claude Code closes the conversation
  • Ports are taken on demand - a server binds its port on the first browser call, not at startup, and releases it 5 minutes after its last tab closes. A chat that never touches the browser never occupies a slot.

Running the agent on another machine

The extension only connects to 127.0.0.1, deliberately - it will not talk to a remote WebSocket. If your MCP gateway runs on a different box than your browser, forward the port range over SSH.

Recipe below contributed by @bkuri, who ran into exactly this and solved it. Linux + systemd; needs autossh locally and your public key already on the server:

# ~/.config/systemd/user/browser-mcp-tunnel.service
[Unit]
Description=SSH tunnel for browser-mcp WebSocket (ports 9876-9895)
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/bin/sh -c '/usr/bin/autossh -M 0 -N \
  -o ServerAliveInterval=30 -o ServerAliveCountMax=3 \
  -o ExitOnForwardFailure=yes -o LogLevel=ERROR \
  $(for p in $(seq 9876 9895); do printf " -L %s:127.0.0.1:%s" "$p" "$p"; done) \
  server-name'
Restart=on-failure
RestartSec=5
Environment="AUTOSSH_GATETIME=0"

[Install]
WantedBy=default.target

Replace server-name, then systemctl --user enable --now browser-mcp-tunnel.service.

The original recipe listed ports 9876-9885 by hand - the range was ten back then. It is twenty now, so the loop above generates them instead of hard-coding a list that goes stale the next time the range changes.

Built-in Provider Integrations

browser_extract_token navigates to the provider's API settings page and guides token extraction:

ProviderToken FormatDashboard
Stripesk_test_... / sk_live_...stripe.com/apikeys
HubSpotpat-...app.hubspot.com
Slackxoxb-...api.slack.com/apps
ShopifyAdmin API tokenadmin.shopify.com
PipedriveUUIDapp.pipedrive.com
CalendlyJWTcalendly.com
Mailchimp...-us1admin.mailchimp.com
GoogleOAuth Clientconsole.cloud.google.com
LinkedInClient ID/Secretlinkedin.com/developers

Architecture

extension/
  manifest.json       # Manifest V3
  background.js       # Service worker - Chrome API dispatcher, session tab groups
  offscreen.js        # Persistent WebSocket bridge (multi-port scanning)
  popup.html/js       # Status UI - sessions, tabs, action log

mcp-server/
  index.js            # MCP server (stdio) + WebSocket client
  tools.js            # 40 tool definitions
  bin/cli.js          # Install CLI

How It Works

  1. Claude Code starts → spawns MCP server via stdio
  2. MCP server binds to first available port (9876-9895)
  3. Extension's offscreen document scans ports every 2s
  4. WebSocket connection established
  5. Commands flow: Claude Code → MCP → Extension → Chrome APIs
  6. Process auto-exits when Claude Code closes (stdin detection)

Keeping it updated

Browser MCP has two parts, and they update independently - how the extension updates depends on how you installed it:

Shortened here. Read the whole README on GitHub.

Tools it gives your agents (34)

ToolWhat it does
browser_navigateNavigate the active browser tab to a URL. Reuses the current tab by default (no tab spam). Pass new_tab=true only when you need to keep the current page open.
browser_get_page_contentGet the content of the current page as text or HTML.
browser_screenshotTake a screenshot of the visible area of the current tab. Returns base64 PNG, or saves to disk if path is provided.
browser_execute_scriptExecute JavaScript code in the context of the current page. Returns the result.
browser_clickClick an element on the page. Supports CSS selectors AND text-based selectors. Auto-scrolls element into view.
browser_fillFill a form input field with a value. Supports CSS selectors AND text-based selectors. Auto-scrolls and focuses the element. Works on CSP-strict sites via Chrome Debugger API.
browser_press_keyPress a keyboard key (Enter, Tab, Escape, ArrowDown, etc.). Useful for submitting forms, navigating dropdowns, closing dialogs. Supports modifier keys (ctrl, alt, shift, meta).
browser_scrollScroll the page to an element or by pixel amount. Useful for reaching elements below the fold.
browser_waitWait for an element to appear on the page. Supports CSS and text-based selectors.
browser_hoverHover over an element to trigger tooltips, dropdown menus, or hover states. Supports CSS and text selectors.
browser_select_optionSelect an option from a dropdown menu. Works with native <select> elements AND custom dropdowns (Angular Material, React Select, etc.).
browser_dismiss_overlaysDismiss visible popups, modals, tooltips, banners, and "Are you sure?"-style overlays in one call.
browser_set_comboboxSet value(s) on an autocomplete/combobox input. Handles the click → type query → wait for filtered listbox → click option flow as one MCP call. Supports multi-select (e.g., Languages on Meta Ads).
browser_drop_fileUpload a file by finding a hidden <input type="file"> within a drag-drop zone's subtree (or parent up to 2 levels). Use when browser_upload_file fails because the dropzone has no visible file input.
browser_set_dateRobustly set a date input — handles native <input type="date">, masked text inputs (e.g. MM/DD/YYYY), and calendar pickers (MUI, react-datepicker, AntD, Lexical/Meta).
browser_handle_dialogHandle JavaScript alert(), confirm(), or prompt() dialogs. Call this BEFORE triggering the action that causes the dialog. Waits for the dialog to appear, then accepts or dismisses it.
browser_wait_for_networkWait for a network request to complete. Useful after clicking buttons that trigger API calls — ensures data is loaded before reading the page.
browser_fetchMake an HTTP request from the extension background (NOT subject to CORS). Use this when page-context fetch would be blocked by CORS or CSP.
browser_list_tabsList all open browser tabs with their URLs and titles.
browser_get_cookiesGet cookies for a specific domain.
browser_get_local_storageRead localStorage from the current page. Pass key for a specific value, or omit for all.
browser_set_cookiesSet one or more cookies for a domain.
browser_set_local_storageSet a localStorage key-value pair on the current page.
browser_console_logsGet recent console.log/warn/error messages from the page. Installs a lightweight interceptor on first call. Returns the last N console messages.
browser_ask_userShow an overlay dialog asking the user to perform an action or provide information (credentials, 2FA, CAPTCHA, OAuth consent). Can include input fields for the user to fill in. Returns user responses.
browser_list_framesList all frames (iframes) in the current page with their URLs and indices.
browser_select_frameExecute JavaScript in a specific iframe by frame index. Use browser_list_frames first to find the right index.
browser_get_new_tabGet the most recently opened tab (useful after clicking links that open new tabs, OAuth popups, etc.).
browser_switch_tabSwitch to a specific browser tab by ID. Get tab IDs from browser_list_tabs or browser_get_new_tab.
browser_close_tabClose a browser tab by ID. Only tabs owned by the current session can be closed.
browser_upload_fileUpload a file to a <input type="file"> element on the page. Uses Chrome Debugger API to set files programmatically — no dialog needed.
browser_extract_tokenNavigate to a provider's API settings page so you can read its API token from the page.
browser_solve_captchaDetect and solve CAPTCHAs on the current page. Auto-detects reCAPTCHA v2/v3, hCaptcha, Cloudflare Turnstile, and FunCaptcha.
browser_aboutReturns Browser MCP info and pre-filled URLs the user can click to submit feature wishes, share use-cases, or report bugs.

Signals

Tools captured
34
Advanced
Delivery
browser-mcp MCP server → your ahel gateway (mcp.ahel.ai) → every connected AI client.
Catalog kind
mcp-server
Gateway key
io-github-agent360dk-browser-mcp
Source
github.com/Agent360dk/browser-mcp