Browser Devtools MCP
@serkan-ozal
About Browser Devtools MCP
A Playwright-based MCP server that exposes a live browser as a traceable, inspectable, debuggable and controllable execution environment for AI agents.
Config
Add this server to your MCP-compatible client using the configuration below.
{
"mcpServers": {
"browser-devtools": {
"command": "npx",
"args": [
"-y",
"browser-devtools-mcp"
]
}
}
}Tools
51ARIA snapshot of the page or a scoped element. Returns a tree with refs (e1, e2, ...) and a refs map. Use refs in interaction tools: selector "e1" or "@e1" to click/fill that element. Output includes URL, title, and YAML tree. Refs are valid until next snapshot or navigation. interactiveOnly: only interactive elements get refs; omit for content roles (headings, etc.) too. cursorInteractive: true adds refs for clickable elements without ARIA (e.g. div with cursor:pointer/onclick). Use with a11y_take-ax-tree-snapshot for full UI analysis.
Combines Chromium AX tree with runtime visual diagnostics (bounding box, visibility, viewport). Use to detect: elements with role/name but hidden or off-screen; layout/geometry issues; overlap/occlusion (enable checkOcclusion). When investigating UI/layout or when clicks fail on seemingly visible elements, set checkOcclusion:true—it uses elementFromPoint() at center+corners to find what is actually on top. boundingBox is from getBoundingClientRect() (viewport coords; layout box only). selectorHint is best-effort (data-testid/data-selector/id). Use with a11y_take-aria-snapshot for full UI analysis.
Gets the HTML content of the current page. By default, all <script> tags are removed from the output unless "removeScripts" is explicitly set to "false".
Gets the visible text content of the current page.
Saves the current page as a PDF file.
Starts video recording of the browser page. Recording captures all page interactions until content_stop-recording is called. Uses Playwright's native screencast API — works in all modes (headless, headed, persistent, CDP attach). Only supported on Chromium-based browsers.
Stops video recording of the browser page and saves the video file. Must be called after content_start-recording. The video is saved as a WebM file.
Takes a screenshot of the current page or a specific element. Do NOT use for page structure—use ARIA/AX snapshots instead. Use only for visual verification (design check, visual bug, contrast, layout). Screenshot is saved to disk; use includeBase64 only when the file cannot be read from the returned path (e.g. remote, container).
Returns the current debugging status including: - Whether debugging is enabled - Source map status - Exceptionpoint state - Count of tracepoints, logpoints, and watches - Snapshot statistics
Resolves a generated/bundled code location to its original source via source maps. Useful for translating minified stack traces or bundle line numbers to original TypeScript/JavaScript source. Requires a page with debugging context (debugging is auto-enabled on first use). Input: generated script URL, line, column (1-based). Output: original source path, line, column when a source map is available.
Puts a non-blocking tracepoint at the specified location. When hit, a snapshot of the call stack and local variables is captured automatically without pausing execution. The urlPattern matches script URLs. Special characters are auto-escaped. Examples: - "app.js" matches scripts containing "app.js" - "bundle.min.js" matches scripts containing "bundle.min.js" DO NOT escape characters yourself (e.g., don't use "app\.js"). Returns resolvedLocations: number of scripts where the tracepoint was set. If 0, the pattern didn't match any loaded scripts.
Removes a tracepoint, logpoint, or watch expression by ID. `type`: `tracepoint`, `logpoint`, or `watch`. `id`: the probe or watch ID (from list-probes).
Lists tracepoints, logpoints, and/or watch expressions. Optional `types`: array of `tracepoint`, `logpoint`, `watch`. If omitted or empty, returns all.
Removes tracepoints, logpoints, and/or watch expressions. Optional `types`: array of `tracepoint`, `logpoint`, `watches`. If omitted or empty, clears all.
Puts a logpoint at the specified location. When the logpoint is hit, the logExpression is evaluated and the result is captured in the snapshot's logResult field. Logpoints are lightweight - they only capture the log expression result, NOT call stack or watch expressions. Use tracepoints for full debug context. urlPattern matches script URLs (e.g., "app.js"). Auto-escaped, do not add backslashes. logExpression: a single JavaScript expression (e.g. "user.name", "JSON.stringify({ a, b })", or "{ discountAmount, finalAmount, n }"). Object literals are supported; for maximum compatibility prefer a single variable or JSON.stringify(...). Returns resolvedLocations: 0 means pattern didn't match any loaded scripts.
Sets the exception tracepoint state: - "none": Don't capture on exceptions - "uncaught": Capture only on uncaught exceptions - "all": Capture on all exceptions (caught and uncaught) When an exception occurs, a snapshot is captured with exception details.
Retrieves snapshots captured by tracepoints, logpoints, and/or exceptionpoints. Optional `types`: array of `tracepoint`, `logpoint`, `exceptionpoint`. If omitted or empty, returns all. Response fields: `tracepointSnapshots`, `logpointSnapshots`, `exceptionpointSnapshots`. Optional `probeId` filters tracepoint or logpoint snapshots; `fromSequence` and `limit` apply per type. Output trimming: by default only the top 5 call stack frames are returned, only `local` scope(s) are included, and variables per scope are capped at 20. Override with maxCallStackDepth, includeScopes, maxVariablesPerScope.
Clears snapshots captured by tracepoints, logpoints, and/or exceptionpoints. Optional `types`: array of `tracepoint`, `logpoint`, `exceptionpoint`. If omitted or empty, clears all. Optional `probeId`: clear only snapshots for this probe (for tracepoint/logpoint).
Adds a watch expression to be evaluated at every breakpoint hit. Watch expression results are included in the snapshot's watchResults field. Examples: - "user.name" - "this.state" - "items.length" - "JSON.stringify(config)" Watch expressions are evaluated in the context of the paused frame.
Clicks an element. Accepts selector or ref (e.g. e1, @e1). Set waitForNavigation: true when the click opens a new page — waits for navigation then for network idle so snapshot/screenshot see full content.
Drags an element to a target location. Accepts CSS selectors or refs (e.g. e1, @e1) from the last ARIA snapshot.
Fills out an input field. Accepts a CSS selector or a ref from the last ARIA snapshot (e.g. e1, @e1).
Hovers an element on the page. Accepts a CSS selector or a ref from the last ARIA snapshot (e.g. e1, @e1).
Presses a keyboard key with optional "hold" and auto-repeat behavior. Key facts: - keyboard.press(key, { delay }) does NOT trigger OS-style auto-repeat. - Some UI behaviors (especially scrolling) require repeated keydown events. - Use repeat=true + holdMs to approximate real keyboard holding. Execution logic: - If selector is provided, the element is focused first. - If holdMs is omitted or repeat=false: → a single keyboard.press() is executed. - If holdMs is provided AND repeat=true: → keyboard.press() is called repeatedly until holdMs elapses.
Resizes the PAGE VIEWPORT using Playwright viewport emulation (page.setViewportSize). This affects: - window.innerWidth / window.innerHeight - CSS media queries (responsive layouts) - Layout, rendering and screenshots Notes: - This does NOT resize the OS-level browser window. - Runtime switching to viewport=null (binding to real window size) is not supported by Playwright. If you need real window-driven responsive behavior, start the BrowserContext with viewport: null and use the window resize tool instead.
Resizes the REAL BROWSER WINDOW (OS-level window) for the current page using Chrome DevTools Protocol (CDP). This tool works best on Chromium-based browsers (Chromium/Chrome/Edge). It is especially useful in headful sessions when you run with viewport emulation disabled (viewport: null), so the page layout follows the OS window size. Important: - If Playwright viewport emulation is enabled (viewport is NOT null), resizing the OS window may not change page layout. - On non-Chromium browsers (Firefox/WebKit), CDP is not available and this tool will fail.
Select an option in a dropdown. Accepts a CSS selector or a ref from the last ARIA snapshot (e.g. e1, @e1).
Scrolls the page viewport or a specific scrollable element. Modes: - 'by': Scrolls by a relative delta (dx/dy) from the current scroll position. - 'to': Scrolls to an absolute scroll position (x/y). - 'top': Scrolls to the very top. - 'bottom': Scrolls to the very bottom. - 'left': Scrolls to the far left. - 'right': Scrolls to the far right. Use this tool to: - Reveal content below the fold - Jump to the top/bottom without knowing exact positions - Bring elements into view before clicking - Inspect lazy-loaded content that appears on scroll
Navigates to the previous or next page in history. - `direction: "back"` — previous page in history. - `direction: "forward"` — next page in history. In case of multiple redirects, the navigation will resolve with the response of the last redirect. If cannot go back/forward, returns empty response. By default (includeSnapshot: true), an ARIA snapshot with refs is returned. Use `snapshotOptions` for `interactiveOnly` (default false) and `cursorInteractive` (default false), same as a11y_take-aria-snapshot. When `includeScreenshot: true`, the screenshot is always saved to disk; `screenshotFilePath` is returned. By default `outputPath` is the OS temp dir and `name` is "screenshot" (same as content_take-screenshot). Use `screenshotOptions.includeBase64: true` only when the file cannot be read from the returned path (e.g. remote, container).
Navigates to the given URL. **NOTE**: The tool either throws an error or returns a main resource response. The only exceptions are navigation to `about:blank` or navigation to the same URL with a different hash, which would succeed and return empty response. **By default** (`includeSnapshot: true`), an ARIA snapshot with refs is taken after navigation and returned in `output` and `refs`; you can use refs (e1, e2, ...) in interaction tools without calling a11y_take-aria-snapshot separately. Use `snapshotOptions` for `interactiveOnly` (default false) and `cursorInteractive` (default false). Set `includeSnapshot: false` to get only url/status/ok. When `includeScreenshot: true`, the screenshot is always saved to disk; `screenshotFilePath` is returned. By default `outputPath` is the OS temp dir and `name` is "screenshot" (same as content_take-screenshot). Use `screenshotOptions.includeBase64: true` only when the file cannot be read from the returned path (e.g. remote, container).
Reloads the current page. In case of multiple redirects, the navigation resolves with the response of the last redirect. If the reload does not produce a response, returns empty response. By default (includeSnapshot: true), an ARIA snapshot with refs is returned. Use `snapshotOptions` for `interactiveOnly` (default false) and `cursorInteractive` (default false), same as a11y_take-aria-snapshot. When `includeScreenshot: true`, the screenshot is saved to disk; `screenshotFilePath` is returned. Default path/name: OS temp dir and "screenshot" (same as content_take-screenshot). Use `screenshotOptions.includeBase64: true` only when the file cannot be read from the path.
Retrieves console messages/logs from the browser with filtering options.
Retrieves HTTP requests from the browser with filtering options.
Gets the OpenTelemetry trace context (trace id and tracestate) from the live browser page when OTEL is enabled.
Collects Web Vitals (LCP, INP, CLS, TTFB, FCP) with Google thresholds and recommendations. Call after navigation or user actions; use waitMs for more stable LCP/CLS/INP. Some metrics may be unavailable depending on browser and interactions.
Generates new OpenTelemetry compatible trace id and sets it to the current session.
Sets or clears the OpenTelemetry trace context. Empty traceId clears the MCP-pinned trace id (new browser traces get random ids). Empty traceState clears tracestate. Non-empty traceState must be valid W3C tracestate (comma-separated key=value list).
Finds React component(s) for a DOM element via React Fiber (best-effort). Give selector or (x,y); we resolve the element, find __reactFiber$ on it or ancestors, then build the component stack from the host fiber that owns that node. Fiber is not a public API—results vary by dev/prod build; names can be displayName, wrappers, or minified. wrappersDetected/wrapperFrames help with memo/forwardRef/context. If hostMapping.strategy is ancestor-fallback, use a more specific selector or deeper node for better accuracy.
Maps a React component instance to the DOM elements it renders (DOM footprint) by traversing the Fiber graph. Prefer an anchor (anchorSelector or anchorX/anchorY) to target the instance; optionally add a query (componentName, fileNameHint, lineNumber) to search Fiber. With both, we rank candidates and pick the best match near the anchor. React DevTools hook gives reliable root discovery (getFiberRoots); without it we fall back to DOM scan for __reactFiber$ (best-effort). For more reliable roots in a persistent browser, install the React Developer Tools Chrome extension. Debug source is best-effort and may be missing in some builds.
Adds a new scenario. A scenario is a reusable JS script (like execute) that can call tools via callTool(). Scenarios are stored on disk under the scenarios.json file (project-level by default, or global with scope="global").
Updates an existing scenario's description and/or script.
Deletes a scenario by name.
Lists all available scenarios. When scope is omitted, returns scenarios from both project and global scopes (project overrides global for same name).
Searches scenarios by query across both project and global scopes. Uses configurable search strategy (SEARCH_STRATEGY or SCENARIO_SEARCH_STRATEGY env var). Returns matching scenarios ranked by relevance.
Clears stubs installed. - If stubId is provided, clears only that stub. - If stubId is omitted, clears all stubs for the current session/context.
Installs a request interceptor stub that can modify outgoing requests before they are sent. Use cases: - A/B testing / feature flags (inject headers) - Security testing (inject malformed headers / payload) - Edge cases (special characters, large payload) - Auth simulation (add API keys / tokens in headers) Notes: - pattern is a glob matched against the full request URL (picomatch). - This modifies requests; it does not change responses. - times limits how many times the interceptor applies (-1 means infinite).
Lists currently installed stubs for the active browser context/session. Useful to debug why certain calls are being mocked/intercepted.
Installs a response stub for matching requests using glob patterns (picomatch). Use cases: - Offline testing (return 200 with local JSON) - Error scenarios (force 500/404 or abort with timedout) - Edge cases (empty data / huge payload / special characters) - Flaky API testing (chance < 1.0) - Performance testing (delayMs) Notes: - pattern is a glob matched against the full request URL. - stubs are evaluated in insertion order; first match wins. - times limits how many times the stub applies (-1 means infinite).
Waits until the page is network-idle: in-flight requests <= maxConnections for at least idleTimeMs (server-side tracking, no page globals). Use before SPAs, screenshots, or AX snapshots for stable results. With long-polling, increase maxConnections or use shorter idleTimeMs.
Batch-execute multiple tool calls in a single request via custom JavaScript. Reduces round-trips and token usage. **IMPORTANT** - The code is already run inside an async function. Pass only the body (statements). Do NOT wrap in `async function() { ... }` or `async () => { ... }` — that causes a syntax error. Write `await callTool(...); return x;` directly. **IMPORTANT:** - `page` (Playwright Page) is available in the VM — use it for navigation or `page.evaluate()`. - Prefer interaction tools with refs (e1, e2 from a11y_take-aria-snapshot); use raw Playwright only as last resort. - `document`/`window` are not in the VM — use `page.evaluate(() => { ... })` to run code in the browser. - Use `waitForNavigation: true` on interaction_click when the click navigates. - After navigation, do not continue with refs from the previous page — take fresh refs with a11y_take-aria-snapshot first. Bindings: - await callTool(name, input, returnOutput?): async — always use with await. Returns the tool output for in-code use. returnOutput=true also includes it in the response toolOutputs array; false (default) omits it. Throws on failure — execution stops at the first error; partial toolOutputs/logs are still returned. On failure, failedTool in the response identifies which tool caused the error. Max 50 callTool invocations per execution. - console.log/warn/error: captured in the response logs array. - sleep(ms): async delay. Built-ins: Math, JSON, Date, RegExp, Number, String, Boolean, Array, Object, Promise, Map, Set, WeakMap, WeakSet, Symbol, Proxy, Reflect, URL, URLSearchParams, TextEncoder/Decoder, structuredClone, crypto.randomUUID(), AbortController, setTimeout/clearTimeout. NOT available: require, import, process, fs, Buffer, fetch. **Example** — fill form, submit (with navigation wait), then snapshot and screenshot: await callTool('interaction_fill', { selector: 'e3', value: '[email protected]' }); await callTool('interaction_fill', { selector: 'e5', value: 'secret123' }); await callTool('interaction_click', { selector: 'e7', waitForNavigation: true }); // Or with page.locator: await page.locator('button').click(); // Or with page.evaluate: await page.evaluate(() => document.querySelector('button').click()); await callTool('a11y_take-aria-snapshot', {}, true); await callTool('content_take-screenshot', {}, true);
Runs a saved scenario by name. Looks up the scenario in project scope first, then global. The scenario's JS script runs in the same sandbox as execute: callTool(), console, sleep are available. Scenarios can compose other scenarios via callTool('scenario-run', { name: '...' }). Max recursion depth: 5.
Overview
What is Browser Devtools MCP?
Browser Devtools MCP is a Model Context Protocol server that provides AI coding assistants with browser automation and debugging capabilities using Playwright, supporting both execution-level debugging (logs, network requests) and visual debugging (screenshots, ARIA snapshots).
How to use Browser Devtools MCP?
Run the server directly with npx -y browser-devtools-mcp without manual installation. Configure your MCP client (VS Code, Claude, Cursor, etc.) with the command npx -y browser-devtools-mcp. Supports both stdio and streamable-http transports, configurable via CLI arguments --transport and --port.
Key features of Browser Devtools MCP
- Visual inspection via screenshots, ARIA snapshots, HTML extraction
- DOM and code-level debugging with element inspection
- Browser automation: navigation, clicking, form filling, scrolling
- Execution monitoring with console messages and HTTP request tracking
- Figma design comparison with similarity scoring
- OpenTelemetry integration for distributed tracing
Use cases of Browser Devtools MCP
- AI-assisted debugging of web application issues
- Automated testing with browser interaction and screenshot validation
- Accessibility auditing using ARIA and AX tree snapshots
- Performance monitoring with web vitals and network tracking
- Visual comparison of live pages against Figma designs
FAQ from Browser Devtools MCP
What are the prerequisites for using Browser Devtools MCP?
You need Node.js 18+ and an AI assistant with an MCP client (e.g., Cursor, Claude Desktop/Code, VS Code, Windsurf).
How do I install Browser Devtools MCP?
No manual installation is required. Run npx -y browser-devtools-mcp to automatically download and start the server.
What transport modes does Browser Devtools MCP support?
It supports both stdio (default) and streamable-http transports, configurable via --transport CLI argument.
How can I use the React tools?
React tools work best with persistent browser context enabled (BROWSER_PERSISTENT_ENABLE=true). Manually install the "React Developer Tools" Chrome extension for optimal reliability; without it, tools fall back to less reliable DOM scanning.
Can I run Browser Devtools MCP as a remote server?
Yes, start it with --transport=streamable-http --port=3000 and configure your MCP client to connect to the server URL (e.g., http://localhost:3000/mcp).
Frequently asked questions
What are the prerequisites for using Browser Devtools MCP?
You need Node.js 18+ and an AI assistant with an MCP client (e.g., Cursor, Claude Desktop/Code, VS Code, Windsurf).
How do I install Browser Devtools MCP?
No manual installation is required. Run `npx -y browser-devtools-mcp` to automatically download and start the server.
What transport modes does Browser Devtools MCP support?
It supports both stdio (default) and streamable-http transports, configurable via `--transport` CLI argument.
How can I use the React tools?
React tools work best with persistent browser context enabled (`BROWSER_PERSISTENT_ENABLE=true`). Manually install the "React Developer Tools" Chrome extension for optimal reliability; without it, tools fall back to less reliable DOM scanning.
Can I run Browser Devtools MCP as a remote server?
Yes, start it with `--transport=streamable-http --port=3000` and configure your MCP client to connect to the server URL (e.g., `http://localhost:3000/mcp`).
Basic information
More Browser Automation MCP servers
Playwright MCP Server 🎭
executeautomationPlaywright Model Context Protocol Server - Tool to automate Browsers and APIs in Claude Desktop, Cline, Cursor IDE and More 🔌
Yoyo
firecrawl🔥 Official Firecrawl MCP Server - Adds powerful web scraping and search to Cursor, Claude and any other LLM clients.
Firecrawl Mcp Server
mendableai🔥 Official Firecrawl MCP Server - Adds powerful web scraping and search to Cursor, Claude and any other LLM clients.
BrowserTools MCP
AgentDeskAIMonitor browser logs directly from Cursor and other MCP compatible IDEs.
Screenshot Scout
screenshotscoutCapture screenshots of webpages as images or PDFs with Screenshot Scout.
Comments