Provides tools to compare live web page UI against Figma design snapshots, calculating similarity scores using MSSIM, image, and text embeddings.
Facilitates distributed tracing by automatically injecting traces into web pages, collecting UI traces, and supporting trace context propagation for backend correlation.
Offers specialized tools for inspecting React-based web applications, including mapping DOM elements to React components and traversing the React Fiber graph.
Browser DevTools MCP
A powerful Model Context Protocol (MCP) server that provides AI coding assistants with comprehensive browser automation and debugging capabilities using Playwright. This server enables both execution-level debugging (logs, network requests) and visual debugging (screenshots, ARIA snapshots) to help AI assistants understand and interact with web pages effectively.
Overview
Browser DevTools MCP exposes a Playwright-powered browser runtime to AI agents, enabling deep, bidirectional debugging and interaction with live web pages. It supports both visual understanding and code-level inspection of browser state, making it ideal for AI-driven exploration, diagnosis, and automation.
Key Capabilities
Visual Inspection: Screenshots, ARIA snapshots, HTML/text extraction, PDF generation
Design Comparison: Compare live page UI against Figma designs with similarity scoring
DOM & Code-Level Debugging: Element inspection, computed styles, accessibility data
Browser Automation: Navigation, input, clicking, scrolling, viewport control
Execution Monitoring: Console message capture, HTTP request/response tracking
OpenTelemetry Integration: Automatic trace injection into web pages, UI trace collection, and backend trace correlation via trace context propagation
JavaScript Execution: Execute code in browser page context or in Node.js VM sandbox on the server
Session Management: Long-lived, session-based debugging with automatic cleanup
Multiple Transport Modes: Supports both stdio and HTTP transports
Features
Content Tools
Screenshots: Capture full page or specific elements (PNG/JPEG) with image data
HTML/Text Extraction: Get page content with filtering, cleaning, and minification options
PDF Export: Save pages as PDF documents with customizable format and margins
Interaction Tools
Click: Click elements by CSS selector
Fill: Fill form inputs
Hover: Hover over elements
Press Key: Simulate keyboard input
Select: Select dropdown options
Drag: Drag and drop operations
Scroll: Scroll the page viewport or specific scrollable elements with multiple modes (by, to, top, bottom, left, right)
Resize Viewport: Resize the page viewport using Playwright viewport emulation
Resize Window: Resize the real browser window (OS-level) using Chrome DevTools Protocol
Navigation Tools
Go To: Navigate to URLs with configurable wait strategies
Go Back: Navigate backward in history
Go Forward: Navigate forward in history
Run Tools
JS in Browser: Execute JavaScript code inside the active browser page (page context with access to window, document, DOM, and Web APIs)
JS in Sandbox: Execute JavaScript code in a Node.js VM sandbox on the MCP server (with access to Playwright Page, console logging, and safe built-ins)
Observability (O11Y) Tools
Console Messages: Capture and filter browser console logs with advanced filtering (level, search, timestamp, sequence number)
HTTP Requests: Monitor network traffic with detailed request/response data, filtering by resource type, status code, and more
Web Vitals: Collect Core Web Vitals (LCP, INP, CLS) and supporting metrics (TTFB, FCP) with ratings and recommendations based on Google's thresholds
OpenTelemetry Tracing: Automatic trace injection into web pages, UI trace collection (document load, fetch, XMLHttpRequest, user interactions), and trace context propagation for backend correlation
Trace ID Management: Get, set, and generate OpenTelemetry compatible trace IDs for distributed tracing across API calls
Synchronization Tools
Wait for Network Idle: Wait until the page reaches a network-idle condition based on in-flight request count, useful for SPA pages and before taking screenshots
Accessibility (A11Y) Tools
ARIA Snapshots: Capture semantic structure and accessibility roles in YAML format
AX Tree Snapshots: Combine Chromium's Accessibility tree with runtime visual diagnostics (bounding boxes, visibility, occlusion detection, computed styles)
Stub Tools
Intercept HTTP Request: Intercept and modify outgoing HTTP requests (headers, body, method) using glob patterns
Mock HTTP Response: Mock HTTP responses (fulfill with custom status/headers/body or abort) with configurable delay, times limit, and probability (flaky testing)
List Stubs: List all currently installed stubs for the active browser context
Clear Stubs: Remove one or all installed stubs
Figma Tools
Compare Page with Design: Compare the current page UI against a Figma design snapshot and return a combined similarity score using multiple signals (MSSIM, image embedding, text embedding)
React Tools
Get Component for Element: Find React component(s) associated with a DOM element using React Fiber (best-effort)
Get Element for Component: Map a React component instance to the DOM elements it renders by traversing the React Fiber graph
Important Requirements for React Tools:
Persistent Browser Context: React tools work best with persistent browser context enabled (
BROWSER_PERSISTENT_ENABLE=true)React DevTools Extension: For optimal reliability, manually install the "React Developer Tools" Chrome extension in the browser profile. The MCP server does NOT automatically install the extension.
Chrome Web Store: https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi
The extension enables reliable root discovery and component search via
__REACT_DEVTOOLS_GLOBAL_HOOK__Without the extension, tools fall back to scanning DOM for
__reactFiber$pointers (best-effort, less reliable)
Prerequisites
Node.js 18+
An AI assistant (with MCP client) like Cursor, Claude (Desktop or Code), VS Code, Windsurf, etc.
Quick Start
This MCP server (using STDIO or Streamable HTTP transport) can be added to any MCP Client
like VS Code, Claude, Cursor, Windsurf, GitHub Copilot via the browser-devtools-mcp NPM package.
No manual installation required! The server can be run directly using npx, which automatically downloads and runs the package.
CLI Arguments
Browser DevTools MCP server supports the following CLI arguments for configuration:
--transport <stdio|streamable-http>- Configures the transport protocol (defaults tostdio).--port <number>– Configures the port number to listen on when usingstreamable-httptransport (defaults to3000).
MCP Client Configuration
Claude Desktop
Local Server
Add the following configuration into the claude_desktop_config.json file.
See the Claude Desktop MCP docs for more info.
Remote Server (HTTP Transport)
First, start the server with HTTP transport:
Then, go to Settings > Connectors > Add Custom Connector in Claude Desktop and add the MCP server with:
Name:
Browser DevToolsRemote MCP server URL: Point to where your server is hosted (e.g.,
http://localhost:3000/mcpif running locally, orhttps://your-server.com/mcpif hosted remotely)
Claude Code
Run the following command. See Claude Code MCP docs for more info.
Local Server
Remote Server
First, start the server with HTTP transport:
Then add the MCP server:
Replace <SERVER_URL> with your server URL (e.g., http://localhost:3000/mcp if running locally, or https://your-server.com/mcp if hosted remotely).
Cursor
Add the following configuration into the ~/.cursor/mcp.json file (or .cursor/mcp.json in your project folder).
See the Cursor MCP docs for more info.
Local Server
Remote Server
First, start the server with HTTP transport:
Then add the configuration:
Replace <SERVER_URL> with your server URL (e.g., http://localhost:3000/mcp if running locally, or https://your-server.com/mcp if hosted remotely).
VS Code
Add the following configuration into the .vscode/mcp.json file.
See the VS Code MCP docs for more info.
Local Server
Remote Server
First, start the server with HTTP transport:
Then add the configuration:
Replace <SERVER_URL> with your server URL (e.g., http://localhost:3000/mcp if running locally, or https://your-server.com/mcp if hosted remotely).
Windsurf
Add the following configuration into the ~/.codeium/windsurf/mcp_config.json file.
See the Windsurf MCP docs for more info.
Local Server
Remote Server
First, start the server with HTTP transport:
Then add the configuration:
Replace <SERVER_URL> with your server URL (e.g., http://localhost:3000/mcp if running locally, or https://your-server.com/mcp if hosted remotely).
Copilot Coding Agent
Add the following configuration to the mcpServers section of your Copilot Coding Agent configuration through
Repository > Settings > Copilot > Coding agent > MCP configuration.
See the Copilot Coding Agent MCP docs for more info.
Local Server
Remote Server
First, start the server with HTTP transport:
Then add the configuration:
Replace <SERVER_URL> with your server URL (e.g., http://localhost:3000/mcp if running locally, or https://your-server.com/mcp if hosted remotely).
Gemini CLI
Add the following configuration into the ~/.gemini/settings.json file.
See the Gemini CLI MCP docs for more info.
Local Server
Remote Server
First, start the server with HTTP transport:
Then add the configuration:
Replace <SERVER_URL> with your server URL (e.g., http://localhost:3000/mcp if running locally, or https://your-server.com/mcp if hosted remotely).
Smithery
Run the following command. You can find your Smithery API key here. See the Smithery CLI docs for more info.
HTTP Transport
To use HTTP transport, start the server with:
The server exposes the following endpoints:
GET /health- Health checkGET /ping- Ping endpointGET /mcp- MCP protocol infoPOST /mcp- MCP protocol messagesDELETE /mcp- Delete session
Important: When configuring remote MCP servers, use the actual URL where your server is hosted:
If running locally:
http://localhost:3000/mcp(orhttp://127.0.0.1:3000/mcp)If hosted remotely:
https://your-server.com/mcp(replace with your actual server URL)
MCP Inspector
Test the server using the MCP Inspector:
Configuration
The server can be configured using environment variables:
Variable | Description | Default |
| Port for HTTP transport |
|
| Idle session timeout (seconds) |
|
| Interval for checking idle sessions (seconds) |
|
| Close session when socket closes |
|
| Maximum console messages to buffer |
|
| Maximum HTTP requests to buffer |
|
| Run browser in headless mode |
|
| Use persistent browser context (preserves cookies, localStorage, etc.). Required for React tools to work optimally. |
|
| Directory for persistent browser context user data |
|
| Use system-installed Chrome browser instead of Playwright's bundled browser |
|
| Custom browser executable path | (uses Playwright default) |
| Enable OpenTelemetry integration |
|
| OpenTelemetry service name |
|
| OpenTelemetry service version | (none) |
| Directory containing OpenTelemetry bundle files | (uses default) |
| OpenTelemetry exporter type: "otlp/http", "console", or "none" |
|
| OpenTelemetry collector base URL (e.g., "http://localhost:4318") | (none) |
| OpenTelemetry exporter HTTP headers (comma-separated key=value pairs) | (none) |
| User interaction events to instrument (comma-separated, e.g., "click,submit") |
|
| Figma API access token for design comparison | (none) |
| Figma API base URL |
|
Available Tools
Content Tools
Parameters:
outputPath(string, optional): Directory path where screenshot will be saved (default: OS temp directory)name(string, optional): Screenshot name (default: "screenshot")selector(string, optional): CSS selector for element to capturefullPage(boolean, optional): Capture full scrollable page (default: false)type(enum, optional): Image format - "png" or "jpeg" (default: "png")quality(number, optional): The quality of the image, between 0-100. Not applicable to PNG images, only used for JPEG format (default: 100)
Returns:
filePath(string): Full path of the saved screenshot fileimage(object): Screenshot image data with mimeType
Notes:
The
qualityparameter only applies to JPEG images. PNG images are always saved at full qualityLower quality values (e.g., 50-70) result in smaller file sizes but reduced image quality
Quality value of 100 provides maximum quality but larger file sizes
Parameters:
selector(string, optional): CSS selector to limit the HTML content to a specific containerremoveScripts(boolean, optional): Remove all script tags from the HTML (default: true)removeComments(boolean, optional): Remove all HTML comments (default: false)removeStyles(boolean, optional): Remove all style tags from the HTML (default: false)removeMeta(boolean, optional): Remove all meta tags from the HTML (default: false)cleanHtml(boolean, optional): Perform comprehensive HTML cleaning (default: false)minify(boolean, optional): Minify the HTML output (default: false)maxLength(number, optional): Maximum number of characters to return (default: 50000)
Returns:
output(string): The requested HTML content of the page
Parameters:
selector(string, optional): CSS selector to limit the text content to a specific containermaxLength(number, optional): Maximum number of characters to return (default: 50000)
Returns:
output(string): The requested text content of the page
Parameters:
outputPath(string, optional): Directory path where PDF will be saved (default: OS temp directory)name(string, optional): PDF name (default: "page")format(enum, optional): Page format - "Letter", "Legal", "Tabloid", "Ledger", "A0" through "A6" (default: "A4")printBackground(boolean, optional): Whether to print background graphics (default: false)margin(object, optional): Page margins with top, right, bottom, left (default: "1cm" for each)
Returns:
filePath(string): Full path of the saved PDF file
Interaction Tools
Parameters:
selector(string, required): CSS selector for the element to click
Parameters:
selector(string, required): CSS selector for the input fieldvalue(string, required): Value to fill
Parameters:
selector(string, required): CSS selector for the element to hover
Parameters:
key(string, required): Key to press (e.g., "Enter", "Escape", "Tab")
Parameters:
selector(string, required): CSS selector for the select elementvalue(string, required): Value to select
Parameters:
sourceSelector(string, required): CSS selector for the source elementtargetSelector(string, required): CSS selector for the target element
Parameters:
mode(enum, optional): Scroll mode - "by" (relative delta), "to" (absolute position), "top", "bottom", "left", "right" (default: "by")selector(string, optional): CSS selector for a scrollable container. If omitted, scrolls the document viewportdx(number, optional): Horizontal scroll delta in pixels (used when mode="by", default: 0)dy(number, optional): Vertical scroll delta in pixels (used when mode="by", default: 0)x(number, optional): Absolute horizontal scroll position in pixels (used when mode="to")y(number, optional): Absolute vertical scroll position in pixels (used when mode="to")behavior(enum, optional): Native scroll behavior - "auto" or "smooth" (default: "auto")
Returns:
mode(string): The scroll mode usedselector(string | null): The selector of the scroll container if provided; otherwise null (document viewport)behavior(string): The scroll behavior usedbefore(object): Scroll metrics before the scroll action (x, y, scrollWidth, scrollHeight, clientWidth, clientHeight)after(object): Scroll metrics after the scroll action (x, y, scrollWidth, scrollHeight, clientWidth, clientHeight)canScrollX(boolean): Whether horizontal scrolling is possiblecanScrollY(boolean): Whether vertical scrolling is possiblemaxScrollX(number): Maximum horizontal scrollLeftmaxScrollY(number): Maximum vertical scrollTopisAtLeft(boolean): Whether the scroll position is at the far leftisAtRight(boolean): Whether the scroll position is at the far rightisAtTop(boolean): Whether the scroll position is at the very topisAtBottom(boolean): Whether the scroll position is at the very bottom
Usage:
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
Parameters:
width(number, required): Target viewport width in CSS pixels (minimum: 200)height(number, required): Target viewport height in CSS pixels (minimum: 200)
Returns:
requested(object): Requested viewport configuration (width, height)viewport(object): Viewport metrics observed inside the page after resizing:innerWidth,innerHeight: window.innerWidth/innerHeightouterWidth,outerHeight: window.outerWidth/outerHeightdevicePixelRatio: window.devicePixelRatio
Notes:
This affects
window.innerWidth/innerHeight, CSS media queries, layout, rendering, and screenshotsThis 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
Parameters:
width(number, optional): Target window width in pixels (required when state="normal", minimum: 200)height(number, optional): Target window height in pixels (required when state="normal", minimum: 200)state(enum, optional): Target window state - "normal", "maximized", "minimized", or "fullscreen" (default: "normal")
Returns:
requested(object): Requested window change parameters (width, height, state)before(object): Window bounds before resizing (windowId, state, left, top, width, height)after(object): Window bounds after resizing (windowId, state, left, top, width, height)viewport(object): Page viewport metrics after resizing (innerWidth, innerHeight, outerWidth, outerHeight, devicePixelRatio)
Notes:
Works best on Chromium-based browsers (Chromium/Chrome/Edge)
Especially useful in headful sessions when running with viewport emulation disabled (viewport: null)
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
Navigation Tools
Parameters:
url(string, required): URL to navigate to (must include scheme)timeout(number, optional): Maximum operation time in milliseconds (default: 0 - no timeout)waitUntil(enum, optional): When to consider navigation succeeded - "load", "domcontentloaded", "networkidle", or "commit" (default: "load")
Returns:
url(string): Final URL after navigationstatus(number): HTTP status codestatusText(string): HTTP status textok(boolean): Whether navigation was successful (2xx status)
Run Tools
Parameters:
script(string, required): JavaScript code to execute
Returns:
result(any): Result of the evaluation. This value can be of any type, including primitives, arrays, or objects. It represents the direct return value of the JavaScript expression executed in the page context.
Notes:
The code executes in the PAGE CONTEXT (real browser environment):
Has access to window, document, DOM, Web APIs
Can read/modify the page state
Runs with the same permissions as the loaded web page
The code runs in an isolated execution context, but within the page
No direct access to Node.js APIs
Return value must be serializable
Typical use cases:
Inspect or mutate DOM state
Read client-side variables or framework internals
Trigger browser-side logic
Extract computed values directly from the page
Parameters:
code(string, required): JavaScript code to run on the MCP server in a VM sandbox. The code is wrapped in an async IIFE, soawaitis allowed. Usereturn ...to return a valuetimeoutMs(number, optional): Max VM CPU time for synchronous execution in milliseconds (default: 5000, max: 30000)
Returns:
result(any): Return value of the sandboxed code (best-effort JSON-safe). If user returns undefined but logs exist, returns{ logs }. If error occurs, returns{ error, logs }
Available bindings:
page: Playwright Page (main interaction surface)console: captured logs (log/warn/error)sleep(ms): async helper
Safe built-ins:
Math, JSON, Number, String, Boolean, Array, Object, Date, RegExp
isFinite, isNaN, parseInt, parseFloat
URL, URLSearchParams
TextEncoder, TextDecoder
structuredClone
crypto.randomUUID()
AbortController
setTimeout / clearTimeout
NOT available:
require, process, fs, Buffer
globalThis
Notes:
This runs on the MCP SERVER (not in the browser)
This is NOT a security boundary. Intended for trusted automation logic
The timeoutMs parameter limits synchronous execution time, but does not automatically time out awaited Promises
Observability (O11Y) Tools
Parameters:
type(enum, optional): Filter by message level - "ERROR", "WARNING", "INFO", "DEBUG"search(string, optional): Text to search for in messagestimestamp(number, optional): Start time filter (Unix epoch milliseconds)sequenceNumber(number, optional): Only return messages after this sequence numberlimit(object, optional): Limit resultscount(number): Maximum number of messagesfrom(enum): "start" or "end" (default: "end")
Returns:
messages(array): Array of console messages with type, text, location, timestamp, and sequence number
Parameters:
resourceType(enum, optional): Filter by resource type (e.g., "document", "script", "stylesheet")status(object, optional): Filter by status code rangemin(number): Minimum status codemax(number): Maximum status code
ok(boolean, optional): Filter by success/failure (2xx = success)timestamp(number, optional): Start time filter (Unix epoch milliseconds)sequenceNumber(number, optional): Only return requests after this sequence numberlimit(object, optional): Limit resultscount(number): Maximum number of requestsfrom(enum): "start" or "end" (default: "end")
Returns:
requests(array): Array of HTTP requests with URL, method, headers, body, response, timing, and metadata
Parameters:
waitMs(number, optional): Optional wait duration in milliseconds before reading metrics (default: 0, max: 30000). Useful to allow LCP/INP/CLS to settle after interactionsincludeDebug(boolean, optional): If true, returns additional debug details such as entry counts and LCP element hint (default: false)
Returns:
url(string): Current page URLtitle(string): Current page titletimestampMs(number): Unix epoch timestamp (ms) when the metrics were capturedmetrics(object): Raw metric values (null if unavailable):lcpMs(number | null): Largest Contentful Paint in millisecondsinpMs(number | null): Interaction to Next Paint in milliseconds (best-effort approximation)cls(number | null): Cumulative Layout Shift scorettfbMs(number | null): Time to First Byte in millisecondsfcpMs(number | null): First Contentful Paint in milliseconds
ratings(object): Ratings computed from Google thresholds for each metric:lcp,inp,cls,ttfb,fcp: Each contains:rating(enum): "good", "needs_improvement", "poor", or "not_available"value(number | null): Metric valueunit(enum): "ms" or "score"thresholds(object): Thresholds used for rating (good, poor)
recommendations(object): Recommendations based on measured values:coreWebVitalsPassed(boolean): True if all Core Web Vitals are rated "good"summary(array): High-level summary and prioritization guidancelcp,inp,cls,ttfb,fcp(array): Specific recommendations for each metricgeneral(array): General measurement and debugging notes
notes(array): Notes about metric availability, browser limitations, and interpretationdebug(object, optional): Optional debug details (when includeDebug=true):waitMs(number): Actual wait duration usedentries(object): Counts of PerformanceEntry types used to compute metricslastLcpSelectorHint(string | null): Best-effort selector hint for the last LCP elementlastLcpTagName(string | null): Tag name of the last LCP element
Core Web Vitals Thresholds:
LCP (Largest Contentful Paint): good <= 2500ms, poor > 4000ms
INP (Interaction to Next Paint): good <= 200ms, poor > 500ms
CLS (Cumulative Layout Shift): good <= 0.1, poor > 0.25
Supporting Metrics Thresholds:
TTFB (Time to First Byte): good <= 800ms, poor > 1800ms
FCP (First Contentful Paint): good <= 1800ms, poor > 3000ms
Usage:
Call after navigation and after user actions
If you need more stable LCP/CLS/INP, pass waitMs (e.g., 1000-3000ms)
Some metrics may be unavailable depending on browser support and whether interactions occurred
Parameters:
No input parameters
Returns:
traceId(string, optional): The OpenTelemetry compatible trace id of the current session if available
Note: Requires OpenTelemetry to be enabled (OTEL_ENABLE=true).
Parameters:
No input parameters
Returns:
traceId(string): The generated new OpenTelemetry compatible trace id
Note: Requires OpenTelemetry to be enabled (OTEL_ENABLE=true). The new trace ID is automatically set and will be used for all subsequent traces in the session.
Parameters:
traceId(string, optional): The OpenTelemetry compatible trace id to be set. Leave it empty to clear the session trace id, so no OpenTelemetry trace header will be propagated from browser throughout the API calls
Returns:
No return value
Note: Requires OpenTelemetry to be enabled (OTEL_ENABLE=true). When a trace ID is set, it will be propagated in HTTP headers (traceparent) for all API calls, enabling correlation with backend traces.
Synchronization Tools
Parameters:
timeoutMs(number, optional): Maximum time to wait before failing (milliseconds, default: 30000)idleTimeMs(number, optional): How long the network must stay idle continuously before resolving (milliseconds, default: 500)maxConnections(number, optional): Idle threshold - network is considered idle when in-flight requests <= maxConnections (default: 0)pollIntervalMs(number, optional): Polling interval used to sample the in-flight request count (milliseconds, default: 50)
Returns:
waitedMs(number): Total time waited until the network became idle or the tool timed outidleTimeMs(number): Idle duration required for successtimeoutMs(number): Maximum allowed wait timemaxConnections(number): Idle threshold usedpollIntervalMs(number): Polling interval usedfinalInFlightRequests(number): The last observed number of in-flight requestsobservedIdleMs(number): How long the in-flight request count stayed <= maxConnections
Usage:
Use before interacting with SPA pages that load data asynchronously
Use before taking screenshots or AX tree snapshots for more stable results
Use after actions that trigger background fetch/XHR activity
Note: This tool uses server-side tracking, so it works reliably even with strict CSP. It does NOT rely on window globals or page-injected counters.
Accessibility (A11Y) Tools
Parameters:
selector(string, optional): CSS selector for element to snapshot
Returns:
output(string): Includes the page URL, title, and a YAML-formatted accessibility tree
Usage:
Use in combination with
accessibility_take-ax-tree-snapshotfor comprehensive UI analysisProvides semantic structure and accessibility roles
Helps identify accessibility issues and page hierarchy problems
Parameters:
roles(array, optional): Optional role allowlist (button, link, textbox, checkbox, radio, combobox, switch, tab, menuitem, dialog, heading, listbox, listitem, option). If omitted, a built-in set of interactive roles is usedincludeStyles(boolean, optional): Whether to include computed CSS styles for each node (default: true)includeRuntimeVisual(boolean, optional): Whether to compute runtime visual information (bounding box, visibility, viewport) (default: true)checkOcclusion(boolean, optional): If true, checks whether each element is visually occluded by another element using elementFromPoint() sampled at multiple points (default: false)onlyVisible(boolean, optional): If true, only visually visible nodes are returned (default: false)onlyInViewport(boolean, optional): If true, only nodes intersecting the viewport are returned (default: false)textPreviewMaxLength(number, optional): Maximum length of the text preview extracted from each element (default: 80)styleProperties(array, optional): List of CSS computed style properties to extract (default: includes display, visibility, opacity, position, z-index, colors, fonts, etc.)
Returns:
url(string): The current page URL at the time the AX snapshot was capturedtitle(string): The document title of the page at the time of the snapshotaxNodeCount(number): Total number of nodes returned by Chromium Accessibility.getFullAXTree before filteringcandidateCount(number): Number of DOM-backed AX nodes that passed role filtering before enrichmentenrichedCount(number): Number of nodes included in the final enriched snapshot outputtruncatedBySafetyCap(boolean): Indicates whether the result set was truncated by an internal safety capnodes(array): List of enriched DOM-backed AX nodes combining accessibility metadata with visual diagnostics, including:axNodeId,parentAxNodeId,childAxNodeIds: Tree structurerole,name,ignored: Accessibility propertiesbackendDOMNodeId,domNodeId,frameId: DOM referenceslocalName,id,className,selectorHint: Element identificationtextPreview: Short preview of rendered text contentstyles: Computed CSS styles (if includeStyles is true)runtime: Visual diagnostics including boundingBox, isVisible, isInViewport, and optional occlusion data
Usage:
Use to detect UI issues like elements that exist semantically but are visually hidden or off-screen
Identify wrong layout/geometry, styling issues, and overlap/stacking/occlusion problems
ALWAYS use
checkOcclusion: truewhen investigating UI/layout problemsUse alongside
a11y_take-aria-snapshottool for complete UI analysis
Stub Tools
Parameters:
pattern(string, required): Glob pattern matched against the full request URL (picomatch)modifications(object, optional): Request modifications to applyheaders(object, optional): Headers to merge into the outgoing request headersbody(string | object, optional): Override request body. If object/array, it will be JSON-stringifiedmethod(string, optional): Override HTTP method (e.g., POST, PUT)
delayMs(number, optional): Artificial delay in milliseconds before continuing the request (default: 0)times(number, optional): Apply only N times, then let through. Omit for infinite
Returns:
stubId(string): Unique id of the installed stubkind(string): Stub kind (always "intercept_http_request")pattern(string): Glob pattern usedenabled(boolean): Whether the stub is enableddelayMs(number): Applied artificial delay in millisecondstimes(number): Max applications (-1 means infinite)
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)
Parameters:
pattern(string, required): Glob pattern matched against the full request URL (picomatch)response(object, required): Mock response configurationaction(enum, optional): "fulfill" or "abort" (default: "fulfill")status(number, optional): HTTP status code (used when action="fulfill", range: 100-599)headers(object, optional): HTTP headers for the mocked responsebody(string | object, optional): Response body. If object/array, it will be JSON-stringifiedabortErrorCode(string, optional): Playwright abort error code (used when action="abort"), e.g., "timedout"
delayMs(number, optional): Artificial delay in milliseconds before applying the stub (default: 0)times(number, optional): Apply only N times, then let through. Omit for infinitechance(number, optional): Probability (0..1) to apply the stub per request (flaky testing)
Returns:
stubId(string): Unique id of the installed stub (use it to clear later)kind(string): Stub kind (always "mock_http_response")pattern(string): Glob pattern usedenabled(boolean): Whether the stub is enableddelayMs(number): Applied artificial delay in millisecondstimes(number): Max applications (-1 means infinite)chance(number, optional): Apply probability (omit means always)action(string): Applied action ("fulfill" or "abort")status(number, optional): HTTP status (present when action="fulfill")
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)
Parameters:
No input parameters
Returns:
stubs(array): Array of installed stubs, each containing:id(string): Stub idkind(string): Stub kind ("intercept_http_request" or "mock_http_response")enabled(boolean): Whether stub is enabledpattern(string): Glob pattern (picomatch)delayMs(number): Artificial delay in mstimes(number): Max applications (-1 means infinite)usedCount(number): How many times it has been appliedaction(string, optional): For mock_response: "fulfill" or "abort"status(number, optional): For mock_response: HTTP status (if set)
Usage:
Useful to debug why certain calls are being mocked/intercepted
Check stub status and usage statistics
Verify stub configuration before debugging issues
Parameters:
stubId(string, optional): Stub id to remove. Omit to remove all stubs
Returns:
clearedCount(number): Number of stubs removed
Usage:
Remove specific stub by ID when no longer needed
Clear all stubs to reset the browser context
Useful after testing or debugging sessions
Figma Tools
Parameters:
figmaFileKey(string, required): Figma file key (the part after /file/ in Figma URL)figmaNodeId(string, required): Figma node id (frame/component node, usually looks like "12:34")selector(string, optional): Optional CSS selector to screenshot only a specific element instead of the whole pagefullPage(boolean, optional): If true, captures the full scrollable page. Ignored when selector is provided (default: true)figmaScale(number, optional): Optional scale for Figma raster export (e.g., 1, 2, 3)figmaFormat(enum, optional): Optional format for Figma export - "png" or "jpg" (default: "png")weights(object, optional): Optional weights for combining signals. Missing/inactive signals are ignored and weights are renormalized:mssim(number, optional): Weight for MSSIM signalimageEmbedding(number, optional): Weight for image embedding signaltextEmbedding(number, optional): Weight for vision→text→text embedding signal
mssimMode(enum, optional): MSSIM mode - "raw" (stricter) or "semantic" (more layout-oriented, default: "semantic")maxDim(number, optional): Optional preprocessing max dimension forwarded to compare pipelinejpegQuality(number, optional): Optional JPEG quality forwarded to compare pipeline (used only when JPEG encoding is selected internally, range: 50-100)
Returns:
score(number): Combined similarity score in the range [0..1]. Higher means more similarnotes(array): Human-readable notes explaining which signals were used and their individual scoresmeta(object): Metadata about what was compared:pageUrl(string): URL of the page that was comparedpageTitle(string): Title of the page that was comparedfigmaFileKey(string): Figma file key used for the design snapshotfigmaNodeId(string): Figma node id used for the design snapshotselector(string | null): Selector used for page screenshot, if any. Null means full pagefullPage(boolean): Whether the page screenshot was full-pagepageImageType(enum): Image type of the captured page screenshot ("png" or "jpeg")figmaImageType(enum): Image type of the captured Figma snapshot ("png" or "jpeg")
How it works:
Fetches a raster snapshot from Figma (frame/node screenshot)
Takes a screenshot of the live browser page (full page or a specific selector)
Computes multiple similarity signals and combines them into one score:
MSSIM (structural similarity; always available)
Image embedding similarity (optional; may be skipped if provider is not configured)
Vision→text→text embedding similarity (optional; may be skipped if provider is not configured)
Usage:
Prefer 'semantic' MSSIM mode when comparing Figma sample data vs real data (less sensitive to text/value differences)
Use 'raw' MSSIM mode only when you expect near pixel-identical output
If you suspect layout/structure mismatch, run with fullPage=true first, then retry with a selector for the problematic region
Notes explain which signals were used or skipped; skipped signals usually mean missing cloud configuration (e.g., AWS_REGION, inference profile, etc.)
Use cases:
UI regression checks
Design parity validation
"Does this page still match the intended layout?" validation
Automated visual testing
Architecture
Session Management
The server uses session-based architecture where each MCP client connection gets its own browser context and page. Sessions are automatically cleaned up when:
The client disconnects
The session becomes idle (configurable timeout)
The session is explicitly closed
Browser Support
The server supports multiple browser engines:
Chromium (default)
Firefox
WebKit
Browser Configuration:
Headless Mode: By default, browsers run in headless mode (
BROWSER_HEADLESS_ENABLE=true). Set tofalseto see the browser window.Persistent Context: When enabled (
BROWSER_PERSISTENT_ENABLE=true), browser contexts persist across sessions, preserving:Cookies and session data
LocalStorage and IndexedDB
Browser extensions and settings
User preferences
Persistent contexts are shared across sessions and are not automatically closed when sessions end.
Important for React Tools: React tools work best with persistent browser context enabled. This allows you to manually install the React DevTools extension in the browser profile, which enables reliable root discovery and component search via
__REACT_DEVTOOLS_GLOBAL_HOOK__.System Browser: When enabled (
BROWSER_USE_INSTALLED_ON_SYSTEM=true), the server uses the system-installed Chrome browser instead of Playwright's bundled browser. This is useful for:Testing with the exact browser version users have
Using browser extensions installed on the system
Better compatibility with certain web applications
Note: System browser support is currently only available for Chromium/Chrome.
React DevTools Extension Setup:
React tools (
react_get-component-for-element,react_get-element-for-component) work best when the React DevTools extension is installed in the browser profileThe MCP server does NOT automatically install the extension - you must install it manually
Installation Steps:
Enable persistent browser context:
BROWSER_PERSISTENT_ENABLE=trueStart the MCP server (or navigate to a page in headful mode)
Manually install the React Developer Tools extension from Chrome Web Store:
The extension will be available in all subsequent sessions using the same persistent context
Without the Extension: Tools will still work but use best-effort DOM scanning for
__reactFiber$pointers, which is less reliable than using the DevTools hook
Browser instances are shared across sessions for efficiency. Each session gets its own isolated browser context, unless persistent context is enabled (in which case contexts are shared).
Buffering & Filtering
Console messages and HTTP requests are buffered in memory with configurable buffer sizes. Both tools support advanced filtering:
Level-based filtering: Filter by severity/type
Text search: Search within message/request content
Time-based filtering: Filter by timestamp
Incremental retrieval: Use sequence numbers to fetch only new items
Pagination: Limit results with start/end trimming
OpenTelemetry Integration
When enabled (OTEL_ENABLE=true), the server automatically injects OpenTelemetry instrumentation into all web pages navigated by the browser. This enables:
Automatic Trace Collection: UI traces are automatically collected for:
Document load events
Fetch/XHR requests
User interactions (clicks, form submissions, etc.)
Trace Context Propagation: Trace IDs are automatically propagated in HTTP headers (traceparent) for all API calls, enabling:
Correlation between frontend and backend traces
End-to-end distributed tracing across the entire application stack
Trace ID Management: Tools allow you to:
Get the current session's trace ID
Generate new trace IDs
Set custom trace IDs (e.g., from backend trace context)
Exporter Configuration: Traces can be exported to:
OTLP/HTTP: Send to OpenTelemetry collector (configure via
OTEL_EXPORTER_HTTP_URL)Console: Log traces to browser console (for debugging)
None: Collect traces but don't export (for testing)
The OpenTelemetry integration uses a proxy mechanism (/__mcp_otel/) to forward traces from the browser to the configured collector, ensuring proper CORS handling and trace context propagation.
Development
Prerequisites
Node.js 18+
npm or yarn
Setup
Scripts
npm run build- Build TypeScript to JavaScriptnpm run start- Start server with stdio transportnpm run start:http- Start server with HTTP transportnpm run watch- Watch mode for developmentnpm run inspector- Run MCP Inspector (stdio)npm run inspector:http- Run MCP Inspector (HTTP)npm run lint:check- Check code formattingnpm run lint:format- Format code
Use Cases
For AI Coding Assistants
This server enables AI assistants to:
Debug Web Applications: Capture screenshots, inspect DOM, check console errors
Monitor Network Activity: Track API calls, analyze request/response patterns
Distributed Tracing: Enable OpenTelemetry to correlate frontend and backend traces for end-to-end debugging
Test User Flows: Automate navigation and interactions
Visual Verification: Compare visual states, verify UI changes
Design Comparison: Compare live page UI against Figma designs with automated similarity scoring
Content Extraction: Get HTML/text content with filtering and cleaning options
Accessibility Analysis: Use ARIA and AX tree snapshots to understand page structure and detect UI issues
Performance Analysis: Monitor HTTP request timing and failures
Example Workflow
Navigate to a web page using
navigation_go-toWait for network idle with
sync_wait-for-network-idleif needed (for SPA pages)Take a screenshot with
content_take-screenshotto see the current stateCheck console messages with
o11y_get-console-messagesfor errorsMonitor HTTP requests with
o11y_get-http-requeststo see API callsCapture accessibility snapshots with
a11y_take-aria-snapshotandaccessibility_take-ax-tree-snapshotto understand page structureCompare page with Figma design using
compare-page-with-designto validate design parityInteract with elements using
interaction_click,interaction_fill, etc.Extract content using
content_get-as-htmlorcontent_get-as-textSave the page as PDF using
content_save-as-pdffor documentation
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT License - see LICENSE file for details.
Author
Serkan Ozal
Email: serkanozal86@gmail.com
GitHub: @serkan-ozal
Acknowledgments
Built with Playwright for browser automation
Uses Model Context Protocol SDK for MCP implementation
HTTP transport powered by Hono