mcp-browser-dev-tools
mcp-browser-dev-tools is a local MCP server that lets AI clients inspect browser state through Chromium DevTools Protocol or Firefox WebDriver BiDi.
It is designed for a local trust boundary:
AI client -> MCP over stdio -> local broker -> browser adapter -> page target
What You Get
- A stdio MCP server for local desktop and terminal clients
- Browser discovery and attach/detach for Chrome, Edge, other Chromium-family browsers, and Firefox
- Inspection tools for DOM lookup, richer element details, console messages, network requests, screenshots, tab listing, and buffered events
- Page interaction tools for navigation, reload, click, hover, type, select, key presses, scroll, and viewport overrides
- Optional JavaScript evaluation behind an explicit environment flag
- Helper commands to check browser connectivity, launch a debug-enabled browser, and relay CDP traffic across a local machine boundary
Requirements
- Node.js
24+ - A local browser exposing either CDP or BiDi
- Loopback endpoints by default; remote endpoints require an explicit opt-in flag
Install
The published package name stays mcp-browser-dev-tools. The preferred installed CLI command is mbdt.
One-off execution with npx:
npx -y mcp-browser-dev-tools serve
Global install:
npm install -g mcp-browser-dev-tools
mbdt serve
Project-local install:
npm install mcp-browser-dev-tools
npx mbdt serve
Try It Locally
You can smoke-test the broker before wiring it into an MCP client.
For Windows, WSL, macOS, and Linux-specific setup paths, see docs/setup.md.
Quick Chromium flow:
# Launch a local browser with remote debugging enabled.
# open waits for the debug endpoint and prints the doctor summary automatically.
npx -y mcp-browser-dev-tools open about:blank --family chromium
If you want to verify a specific app URL too:
npx -y mcp-browser-dev-tools doctor --url http://127.0.0.1:3000
Then start the MCP server in a dedicated terminal:
npx -y mcp-browser-dev-tools serve
serve stays attached to stdio because MCP clients talk to it over standard input and output. Run it in its own terminal or let your MCP client spawn it directly.
If you want one broker to handle Chromium and Firefox at the same time, run it in auto mode and point each adapter at its own endpoint:
MCP_BROWSER_FAMILY=auto \
CDP_BASE_URL=http://127.0.0.1:9223 \
FIREFOX_BIDI_WS_URL=ws://127.0.0.1:9222 \
npx -y mcp-browser-dev-tools serve
Use distinct ports in auto mode. A practical local split is Firefox on 9222 and Chrome or Edge on 9223.
If you already have a browser listening on http://127.0.0.1:9222, doctor is enough to confirm that the broker can reach it:
CDP_BASE_URL=http://127.0.0.1:9222 npx -y mcp-browser-dev-tools doctor
If you need to bridge Windows Chrome into WSL without changing WSL networking mode, run the relay on Windows and point WSL at the relay port instead. The full procedure is in docs/setup.md.
MCP Client Configuration
Use the same server command across MCP clients:
npx -y mcp-browser-dev-tools serve
If you installed the package already, the shorter equivalent is:
mbdt serve
Codex
Add the server with the Codex CLI:
codex mcp add browser-devtools \
--env MCP_BROWSER_FAMILY=auto \
--env CDP_BASE_URL=http://127.0.0.1:9223 \
--env FIREFOX_BIDI_WS_URL=ws://127.0.0.1:9222 \
-- npx -y mcp-browser-dev-tools serve
Equivalent ~/.codex/config.toml entry:
[mcp_servers.browser-devtools]
command = "npx"
args = ["-y", "mcp-browser-dev-tools", "serve"]
[mcp_servers.browser-devtools.env]
MCP_BROWSER_FAMILY = "auto"
CDP_BASE_URL = "http://127.0.0.1:9223"
FIREFOX_BIDI_WS_URL = "ws://127.0.0.1:9222"
If Codex runs in WSL but the browser runs on Windows, run the broker on Windows too so it can connect to Windows loopback directly. This avoids relay and WSL networking issues.
Example ~/.codex/config.toml entry for Firefox on Windows:
[mcp_servers.browser-devtools]
startup_timeout_sec = 30
command = "/mnt/c/nvm4w/nodejs/node.exe"
args = ["-e", "process.env.MCP_BROWSER_FAMILY='firefox';process.env.FIREFOX_BIDI_WS_URL='ws://127.0.0.1:9222';import('//wsl.localhost/<wsl-distro>/<repo-wsl-path>/src/cli.mjs').then(({ runCli }) => runCli(['serve'])).catch((error) => { console.error(error?.stack || String(error)); process.exit(1); });"]
Example auto mode entry for Firefox plus Chrome or Edge on Windows:
[mcp_servers.browser-devtools]
startup_timeout_sec = 30
command = "/mnt/c/nvm4w/nodejs/node.exe"
args = ["-e", "process.env.MCP_BROWSER_FAMILY='auto';process.env.CDP_BASE_URL='http://127.0.0.1:9223';process.env.FIREFOX_BIDI_WS_URL='ws://127.0.0.1:9222';import('//wsl.localhost/<wsl-distro>/<repo-wsl-path>/src/cli.mjs').then(({ runCli }) => runCli(['serve'])).catch((error) => { console.error(error?.stack || String(error)); process.exit(1); });"]
Replace <wsl-distro> and <repo-wsl-path> with your own WSL distro name and repository path.
Claude Code
Add the server with Claude Code:
claude mcp add browser-devtools --scope user \
--env MCP_BROWSER_FAMILY=auto \
--env CDP_BASE_URL=http://127.0.0.1:9223 \
--env FIREFOX_BIDI_WS_URL=ws://127.0.0.1:9222 \
-- npx -y mcp-browser-dev-tools serve
On native Windows, wrap npx with cmd /c:
claude mcp add browser-devtools --scope user --env MCP_BROWSER_FAMILY=auto --env CDP_BASE_URL=http://127.0.0.1:9223 --env FIREFOX_BIDI_WS_URL=ws://127.0.0.1:9222 -- cmd /c npx -y mcp-browser-dev-tools serve
Equivalent .mcp.json shape:
{
"mcpServers": {
"browser-devtools": {
"command": "npx",
"args": ["-y", "mcp-browser-dev-tools", "serve"],
"env": {
"MCP_BROWSER_FAMILY": "auto",
"CDP_BASE_URL": "http://127.0.0.1:9223",
"FIREFOX_BIDI_WS_URL": "ws://127.0.0.1:9222"
}
}
}
}
Cursor
Cursor reads MCP servers from mcp.json:
{
"mcpServers": {
"browser-devtools": {
"command": "npx",
"args": ["-y", "mcp-browser-dev-tools", "serve"],
"env": {
"MCP_BROWSER_FAMILY": "auto",
"CDP_BASE_URL": "http://127.0.0.1:9223",
"FIREFOX_BIDI_WS_URL": "ws://127.0.0.1:9222"
}
}
}
}
Common Variants
Auto mode with both browsers attached to one MCP server:
{
"MCP_BROWSER_FAMILY": "auto",
"CDP_BASE_URL": "http://127.0.0.1:9223",
"FIREFOX_BIDI_WS_URL": "ws://127.0.0.1:9222"
}
Firefox:
{
"MCP_BROWSER_FAMILY": "firefox",
"FIREFOX_BIDI_WS_URL": "ws://127.0.0.1:9222"
}
Microsoft Edge:
{
"MCP_BROWSER_FAMILY": "edge",
"CDP_BASE_URL": "http://127.0.0.1:9222"
}
Windows browser bridged into WSL through the relay:
{
"MCP_BROWSER_FAMILY": "chromium",
"MCP_BROWSER_ALLOW_REMOTE_ENDPOINTS": "1",
"CDP_BASE_URL": "http://<windows-host-ip>:9223"
}
If you only want a single CDP browser, switch MCP_BROWSER_FAMILY back to chromium or edge and omit FIREFOX_BIDI_WS_URL.
Enable evaluate_js:
{
"MCP_BROWSER_ENABLE_EVAL": "1"
}
Commands
serveruns the MCP broker over stdiodoctor [--url URL]checks browser reachability, local display state, and optional page accessopen <url>launches a local browser with remote debugging enabledrelayforwards TCP traffic, useful for Windows-to-WSL DevTools bridging--helpandhelpprint usage--versionandversionprint the package version
Examples:
mbdt doctor
mbdt doctor --url http://127.0.0.1:3000
mbdt open http://127.0.0.1:3000 --family chromium
mbdt open http://127.0.0.1:3000 --family edge --port 9223 --user-data-dir /tmp/mbdt-edge
mbdt open about:blank --family firefox --user-data-dir /tmp/mbdt-firefox
mbdt relay --wsl
Configuration
MCP_BROWSER_FAMILYdefaults tochromium; setedgefor Microsoft Edge,firefoxfor Firefox BiDi, orautoto multiplex both adaptersCDP_BASE_URLdefaults tohttp://127.0.0.1:9222FIREFOX_BIDI_WS_URLdefaults tows://127.0.0.1:9222; when pointed at the root Firefox remote debugging port, the broker connects to the/sessionwebsocket and creates a BiDi session there- in
automode, assign CDP and Firefox different ports so both browsers can run at once MCP_BROWSER_EVENT_BUFFER_SIZEsets the per-session buffered event limitMCP_BROWSER_ENABLE_EVAL=1enablesevaluate_jsMCP_BROWSER_ALLOW_REMOTE_ENDPOINTS=1allows non-loopback CDP or BiDi endpointsMCP_BROWSER_ALLOW_REMOTE_CDP=1is still accepted as a legacy aliasMCP_PROTOCOL_VERSIONoverrides the advertised MCP protocol version
The open command also requires MCP_BROWSER_ALLOW_REMOTE_ENDPOINTS=1 before it will bind Chromium remote debugging to a non-loopback address.
The relay command defaults to 127.0.0.1:9223 -> 127.0.0.1:9222. Non-loopback relay binds require either --wsl on Windows or MCP_BROWSER_ALLOW_REMOTE_ENDPOINTS=1.
Exposed Tools
browser_statusreturns broker metadata too:serverNameandserverVersionInautomode it also includes per-browser adapter status underbrowserslist_tabsInautomode eachtargetIdis namespaced aschromium:<id>orfirefox:<id>list_sessionsInautomode eachsessionIdis namespaced the same wayattach_tabdetach_tabget_page_statenavigatereloadclickhovertypeselectpress_keyscrollset_viewportget_console_messagesget_network_requestsget_documentinspect_elementtake_screenshotget_events
evaluate_js is intentionally disabled by default. Enable it only when you want the broker to allow page-side code execution.
For tools that take sessionId, call attach_tab first and reuse the returned session.
Locator Syntax
Interaction and inspection tools accept these locator forms:
- CSS selectors such as
#app button.primaryorcss=.modal button - visible-text lookup such as
text=Open settings - role plus accessible name such as
role=button[name="Open settings"] - accessible-name lookup such as
name=Open settings
inspect_element returns layout and accessibility-focused metadata including bounding box, visibility flags, interactivity flags, accessible name, inferred role, and a subset of computed styles. Invalid CSS selectors now return an explicit locator error instead of a generic DOM failure.
Screenshot Output
take_screenshot returns base64 image data plus metadata such as mimeType, byteLength, and scope. Pass selector to capture a single element instead of the full page.
Browser Notes
- Chromium uses the standard DevTools endpoints at
/json/versionand/json/list - Firefox support expects a direct BiDi websocket endpoint
- In WSL, Linux browser executables are preferred before Windows fallback paths
- For Windows Chrome + WSL, prefer the
relaycommand over changing Chrome's remote debugging bind
Why Not Playwright?
Playwright is still the stronger choice for deterministic browser automation and end-to-end tests. It has a more mature locator model, assertions, waiting semantics, tracing, and CI story.
mcp-browser-dev-tools solves a different problem:
- it is MCP-native, so AI clients call a bounded tool surface instead of generating and executing Playwright scripts
- it attaches to an already-open browser tab and inspects the current session state, cookies, login state, extensions, console, and network history
- it is designed for local AI debugging workflows, including loopback-only defaults, opt-in evaluation, and the Windows-to-WSL relay path
- it presents one MCP interface across Chromium CDP and Firefox BiDi instead of requiring the AI client to know browser protocol details
Use Playwright when you want reproducible automation. Use this project when you want an AI assistant to inspect and manipulate a live browser session through MCP.
Debugging Notes
attach_tabnow seeds network history from the Performance API so already-loaded pages still show useful requests- console buffers include source URL, line and column where the browser reports them, plus stack frames when available
get_page_statereports the current URL, title, viewport, and scroll position without enablingevaluate_js
Safety Defaults
- The broker only allows loopback browser endpoints unless you opt in
- The default tool surface is read-focused
- Arbitrary page evaluation is opt-in
- Clients interact with a bounded MCP tool surface instead of raw browser protocol calls
Development
corepack enable
pnpm install
pnpm run check
pnpm run pack:check
The repository uses pnpm for local development and CI. End-user installation and publish flows still target the npm registry.
Additional docs: