agentic-browser-mcp
The agentic-browser-mcp server provides browser automation capabilities to MCP clients (Codex, Claude, Cursor, etc.) using Playwright and the Chrome DevTools Protocol.
Session Management: Start or switch between real mode (connects to an existing logged-in Chrome, preserving cookies/sessions/2FA) or isolated mode (launches an independent profile, optionally headless or incognito). Multiple MCP clients can share a single session, and Chrome is auto-launched if not detected.
Navigation: Open any URL in the browser.
Page Inspection: Retrieve a snapshot of interactive elements with ARIA roles, accessible names, and stable ref IDs (e.g. [ref=e3] button "Sign in"). Defaults to viewport-only for token efficiency.
Clicking & Typing: Interact with elements by ref ID or by role + accessible name.
JavaScript Execution: Run arbitrary JS expressions in the page context — read the DOM, access storage, fire network requests, etc.
Storage Access: Read cookies, localStorage, or sessionStorage from the current page.
Console Logs: Retrieve buffered browser console logs, optionally filtered by level (error, warning, log, info).
Human Intervention: Pause automation for manual steps like solving CAPTCHAs or completing logins, returning the current URL and a reason to the user.
Screenshots: Capture a PNG screenshot of the current page (full page or viewport).
Session Cleanup: Explicitly close the session — disconnects CDP for real mode (without killing Chrome) or terminates the browser for isolated mode.
Supports both stdio and http transports for flexible integration.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@agentic-browser-mcpNavigate to wikipedia.org and click the first link"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
agentic-browser-mcp
English | 中文
A standalone MCP server that gives any MCP client (Codex, Claude, Grok, Cursor, …) browser automation on top of Playwright. Drive a real, already-logged-in Chrome through the Chrome DevTools Protocol — share cookies and sessions across agents. The goal: every MCP client you use drives the same browser, with the login state intact.
Features
15 tools:
browser_session,browser_navigate,browser_snapshot,browser_click,browser_type,browser_select_option,browser_hover,browser_tabs,browser_handle_dialog,browser_eval,browser_storage,browser_console,browser_wait_human,browser_screenshot,browser_closeTwo session modes:
real—connectOverCDPto an existing Chrome on port9222(reuse your logged-in profile: cookies, sessions, 2FA)isolated—launchPersistentContextwith an independent profile (headed/headless)
Auto-launch Chrome: if port 9222 is down, the server spawns your Chrome starter script and waits for it — no manual browser launch needed.
Element Ref targeting (Cursor-style):
snapshotnumbers every interactive element with a stableref(e1,e2, …) and returns lines like- [ref=e3] button "Sign in";click/typetarget byreffor precision, or fall back torole+name. It pierces open shadow roots, maps native tags to implicit ARIA roles (<a>→link,<select>→combobox, …), and filters out hidden elements viacheckVisibility()+ non-zero size. Default returns only in-viewport elements (mode=allfor everything) — big token savings on complex pages.Transports:
stdio(default, for Codex-style spawn) andhttp(stateless streamable,--transport http --port 9223).
Related MCP server: Playwright MCP
Requirements
Node.js ≥ 18
Playwright-compatible Chrome/Chromium installed (
google-chrome-stableworks)For
realmode: a Chrome instance running with--remote-debugging-port=9222and a dedicateduser-data-dir(see Start Chrome with CDP)
Path configuration (env vars)
All paths go through env vars with defaults that fall back to the Pi env layout. To deploy on a different device/path, set one or more env vars:
Env var | Default | Purpose |
|
| Root dir; other paths derive from this |
|
| Chrome launch script |
|
| CDP-mode profile dir |
|
| Isolated-mode profile dir |
|
| Chrome startup log |
|
| Chrome DevTools Protocol port |
Override examples:
# Change only the root (others follow)
AGENT_BROWSER_DIR=/data/my-agent node index.mjs
# Fine-grained control
AGENT_BROWSER_CHROME_STARTER=/opt/chrome/launch.sh \
AGENT_BROWSER_CDP_PROFILE=/opt/chrome/profiles/logged-in \
node index.mjsAll paths in error messages and tool descriptions are dynamic — no hardcoded ~/.pi/agent.
Install
git clone https://github.com/q35888/agentic-browser-mcp.git
cd agentic-browser-mcp
npm installConfigure your MCP client
Codex (~/.codex/config.toml)
[mcp_servers.agentic-browser]
type = "stdio"
command = "/usr/bin/node"
args = [ "/path/to/agentic-browser-mcp/index.mjs" ]Any MCP client (stdio)
Spawn node /path/to/agentic-browser-mcp/index.mjs over stdio — standard MCP initialize → tools/list → tools/call.
HTTP mode (long-running single instance)
node index.mjs --transport http --port 9223
# POST MCP requests to http://127.0.0.1:9223/mcpStart Chrome with CDP (for real mode)
Chrome 150+ requires a non-default user-data-dir for remote debugging. Example starter script:
#!/usr/bin/env bash
# ⚠️ Profile path is controlled by AGENT_BROWSER_CDP_PROFILE (default: $HOME/.pi/agent/chrome-cdp-profile).
# No logins? Run sync-profile.sh once to copy them from your daily Chrome.
# Check if a profile has a site's login:
# strings <profile>/Default/Cookies | grep -i <domain> # hits = cookies present
PROFILE="$HOME/.agentic-browser-chrome-profile"
mkdir -p "$PROFILE"
# Fill in graphics session env if spawning from a non-graphical context
export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}"
export WAYLAND_DISPLAY="${WAYLAND_DISPLAY:-wayland-0}"
exec google-chrome-stable \
--remote-debugging-port=9222 \
--user-data-dir="$PROFILE" \
--ozone-platform=wayland \
"$@"
--ozone-platform=waylandis important when Chrome is spawned from a background process: otherwise Chrome's platform heuristic picks X11 and fails withMissing X server / Authorization required. Adjust for your display server (X11 users: drop the flag and ensureDISPLAY/XAUTHORITYare set).
If you don't start Chrome manually, the server auto-launches: first tries the AGENT_BROWSER_CHROME_STARTER script (default $HOME/.pi/agent/start-agent-chrome.sh); if absent, falls back to a builtin direct spawn (cross-platform chrome lookup, zero external deps). To customize, set AGENT_BROWSER_CHROME_STARTER to your own script.
Reusing your daily browser's login state
Chrome 136+ silently ignores --remote-debugging-port on the default profile (security hardening against infostealers), so the dedicated Chrome must use a separate user-data-dir and starts with no logins. To make it carry all the logins from your daily Chrome (Gmail, GitHub, internal SaaS, …), run the sync script:
# With the dedicated Chrome stopped (and daily Chrome idle or closed):
./scripts/sync-profile.shIt copies Cookies / Login Data / Web Data / Local State from your default profile into the dedicated one — on Linux, the GNOME keyring key is shared per-user, so encrypted cookies decrypt transparently. Re-run it whenever you log in to a new site in your daily Chrome. See docs/agent-guide.md, section "Reuse your daily logins", for details.
Tools
Tool | Description |
| Start/switch a session ( |
| Opens a URL. Passing |
| Lists interactive elements with |
| Click by |
| Fill an input by |
| Pick a |
| Hover an element by |
| Manage tabs: |
| Handle JS dialogs (alert/confirm/prompt). Call before the triggering action with |
| Run a JS expression in the page (read DOM/storage/fire requests). |
| Read |
| Reads buffered console logs (optional |
| For CAPTCHAs/manual steps — returns a prompt; the calling agent pauses and waits for the user. |
| Save a PNG to disk. |
| Close the current session ( |
Element targeting (ref)
Every browser_snapshot injects a script that scans the page for interactive elements (links, buttons, inputs, [role]s, [contenteditable], [tabindex], …) and pierces open shadow roots. Each surviving element gets a short ref id (e1, e2, …) via a data-agent-ref attribute. The returned text looks like:
- [ref=e1] link "Docs"
- [ref=e2] searchbox "Search"
- [ref=e3] button "Sign in"Visibility & viewport filtering
An element is included only if it passes both checks:
Visible —
el.checkVisibility({ checkOpacity, checkVisibilityCSS, contentVisibilityAuto })(falling back tocomputed visibility !== 'hidden'on old browsers) and a non-zero bounding rect. This filtersdisplay:none,visibility:hidden,opacity:0,0×0, and parent-hidden elements — the oldoffsetParentcheck missed these (e.g. DuckDuckGo's hidden<input type=radio opacity:0 rect=0×0>that brokefill).In viewport (default
mode=viewport) —rectintersects the viewport. Passmode=allto include off-screen elements too. On a complex page this cuts the snapshot from ~150 elements to ~10, saving ~90% tokens.
Role mapping
Native tags are mapped to their implicit ARIA role so the output matches what Playwright's getByRole() expects for the fallback path: <a href>→link, <button>/<summary>→button, <textarea>/text <input>→textbox, <input type=search>→searchbox, checkbox/radio, <select>→combobox. Explicit role= attributes always win.
Using refs
click { ref: "e3" } # precise — the exact element snapshotted
click { role: "button", name: "Sign in" } # fallback when you have no ref
type { ref: "e2", text: "playwright" }ref is validated against ^e\d+$ and the locator is checked for exactly one match: 0 → "stale ref, re-snapshot"; >1 → "duplicate ref, re-snapshot" (a snapshot-internal error).
Refs are ephemeral. Each
snapshotrenumbers elements from scratch (clearing olddata-agent-refattrs, including inside shadow roots), so arefis only valid until the nextsnapshot. If the page changes (navigation, dynamic content), re-runsnapshotbefore acting. Output is truncated on whole-line boundaries with a…[共 N 项,返回 M 项]summary.
Notes
📌 Multi-tab behavior — Every tool call runs refreshActivePage(s) first. By default it follows the last-created tab, so:
✅
click <a target="_blank">,window.open(),browser_navigateopening a new tab → subsequent operations auto-follow the new tab✅
browser_tabs(list/switch/close/new) for explicit control — an explicitswitchsticks (pinned) until a new tab appears, then auto-follow resumes❌ Manual tab switching in Chrome UI is NOT tracked (Playwright CDP exposes no stable "focused tab" API)
❌
browser_tabs closerefuses the last tab (would force a session rebuild) — usebrowser_closeto end the session
📖 Helping a user set up this MCP? Read docs/agent-guide.md — environment discovery, install, per-client config (Codex/Claude Desktop/Cursor), Chrome setup, verification, and common pitfalls.
🆚 How does this compare to the official @playwright/mcp? See docs/vs-playwright-mcp.md — same Playwright underneath, different trade-offs (login-state reuse, token-efficient snapshots, auto-launched Chrome, Chinese-first tool descriptions).
browser_wait_human: this server has no GUI/TUI. It returns a text prompt; the client agent is expected to surface it and wait for the user to reply.Session sharing: multiple MCP clients connecting to the same server share one Playwright session (and thus one Chrome). Tool calls are serialized to prevent races.
Resource cleanup: on
stdinEOF, transport close, orSIGINT/SIGTERM, the server disposes the session (with a 3s timeout fallback) —isolatedbrowsers won't be orphaned.
Troubleshooting
ECONNREFUSED 127.0.0.1:9222/ Chrome not running — Inrealmode the server probes 9222 vianode:http.get /json/version(agent:falseexplicitly bypasseshttp_proxy/https_proxy, avoiding false "port closed" when your proxy would intercept the localhost probe). Probing TCP alone is not enough — Chrome startup order is TCP first → then DevTools HTTP → then/json/versionresponds; checking only TCP causes a race (TCP up butconnectOverCDPimmediately throws). So it waits for/json/version200. If closed, it callsspawnStarter(): tries theAGENT_BROWSER_CHROME_STARTERscript first (if it exists); otherwise builtin-direct-spawns chrome — cross-platform executable lookup (Linux/usr/bin/google-chrome-stableetc, WindowsProgram Files, macOS/Applications/Google Chrome.app), usingdetached:true+--remote-debugging-port=${CDP_PORT}+--user-data-dir=${CDP_PROFILE}. Polls for up to 20s. If auto-start still fails, launch Chrome manually.fill: Timeout … element is not visible— You likely clicked/typed a hidden element (e.g. a0×0/opacity:0decorative control). Re-runsnapshot; the visibility filter should now exclude it. If a genuinely visible element still fails, its ref may be stale — re-snapshot.ref=eN 未命中(stale ref) — The page changed since the lastsnapshot(navigation, dynamic content, element removed/re-rendered). Re-runsnapshotand use the new ref.ref=eN 命中 N 个(duplicate ref) — A snapshot-internal error (refs should be unique). Re-snapshot; if it persists, file an issue.Snapshot too noisy / too many elements — You're probably on
mode=all. The default ismode=viewport(in-viewport only). Scroll then re-snapshot, or stay on the default.Does
browser_close()kill my real Chrome? — No. UnderconnectOverCDP,browser.close()only drops the CDP connection; the real Chrome process and its tabs survive (verified). It's safe to call.CSS is not defined— (Fixed in newer versions.) The Node-side tool handler must not use browser globals likeCSS/document; only code insidepage.evaluate()runs in the browser.
License
MIT
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- FlicenseBqualityDmaintenancePlaywright wrapper for MCP that enables LLM-powered clients to control a browser for automation tasks.Last updated101
- Alicense-qualityDmaintenanceEnables browser automation and web scraping by exposing Playwright tools through an HTTP-based MCP server. Users can navigate pages, interact with web elements, capture screenshots, and extract structured content using a persistent Chromium instance.Last updatedMIT
- Flicense-qualityCmaintenanceExposes Playwright browser automation as MCP tools, enabling AI assistants to control a real browser tab-by-tab for form filling, navigation, and more, while preserving the user's active session.Last updated
- Alicense-qualityBmaintenanceEnables MCP clients to drive a real, logged-in Chrome browser for web automation tasks like navigation, clicking, typing, and screenshotting.Last updated181MIT
Related MCP Connectors
Hosted real Google Chrome MCP with per-user persistent state. Navigate, click, type, screenshot.
Browser MCP for logged-in tasks. Uses your Chrome — credentials stay local. Zero-token replay.
Provides cloud browser automation capabilities using Stagehand and Browserbase, enabling LLMs to i…
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/q35888/agentic-browser-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server