Skip to main content
Glama

zendriver-mcp

Undetectable browser automation for LLM agents, spoken over MCP.

zendriver-mcp is an MCP server that gives your coding agent (Claude, Cursor, Gemini, Copilot) a real Chrome browser it can actually use on the real web - behind Cloudflare, behind login walls, on pages that detect and block WebDriver.

It's built on Zendriver, which speaks the Chrome DevTools Protocol directly instead of going through WebDriver. That means no navigator.webdriver flag, no headless telltales, and a fingerprint that looks like an ordinary Chrome install.

On top of that foundation, zendriver-mcp layers everything an agent needs to get work done: a token-efficient DOM walker, an accessibility tree with stable uids, performance traces, Lighthouse audits, heap snapshots, human-like input, device emulation, cookie round-tripping, and more - 96 tools across 22 modules.

Highlights

  • Undetectable by design. Zendriver keeps a clean fingerprint; we ship a Cloudflare Turnstile solver, identity overrides (UA, locale, timezone, geolocation), and bezier-curve mouse movement plus gaussian typing timing.

  • Token-efficient DOM. Two ways to see the page - the upstream DOM walker that reports 96% fewer tokens than raw HTML, and a CDP accessibility tree keyed by stable uids that survive re-renders.

  • Full DevTools parity. Performance traces that load in Chrome DevTools, heap snapshots in the standard .heapsnapshot format, Lighthouse audits via the Lighthouse CLI reusing the same browser.

  • Session round-tripping. Export all cookies (including HTTP-only ones) to JSON, re-import on the next session. Log in once, reuse everywhere.

  • Emulation. iPhone 15 Pro, Pixel 8, iPad Pro, and desktop presets; CPU throttling; Slow 3G / Fast 3G / 4G / offline network profiles; force prefers-color-scheme.

  • Screencasts. Write frames to disk as JPEG or PNG at configurable FPS.

Related MCP server: Browser MCP Server Template

Tool catalogue

Module

Tools

browser

start, stop, status

navigation

navigate, back, forward, reload, page info

tabs

new / list / switch / close

elements

click, type, clear, focus, select, upload

query

find element(s), text, attributes, buttons, inputs

content

HTML, text, interaction tree, scroll

storage

cookies (document.cookie), localStorage

logging

network + console logs, wait-for-request

forms

fill form, submit, key press, mouse click

utils

screenshot, execute JS, wait, security audit

stealth

Cloudflare bypass, UA / locale / timezone / geolocation overrides

humanlike

human_click, human_type, estimated_typing_duration

emulation

viewport, device presets, CPU + network throttle, media

devtools

start/stop trace, take heap snapshot

lighthouse

run audit, check CLI availability

screencast

start / stop (writes frame directory)

accessibility

AX snapshot with stable uids, click_by_uid, describe_uid

cookies

export / import / list / clear (CDP-level, all origins)

network_control

block URLs, extra headers, bypass service worker

permissions

grant / reset, list names

proxy

configure / clear (restarts browser with proxy args)

interception

mock_response, fail_requests, list, stop

screencast

+ export_screencast_mp4, check_ffmpeg_available

Full signatures live in the docstrings of src/tools/*.py and are auto-listed by the MCP handshake.

Install

Published on PyPI: https://pypi.org/project/zendriver-mcp/.

Requires Python 3.10+ and a Chrome / Chromium install.

# Zero-setup, re-resolves on every run - great for Claude Desktop configs
uvx zendriver-mcp

# Or install once, invoke many
uv tool install zendriver-mcp
pipx install zendriver-mcp
pip install zendriver-mcp

Use with Claude Desktop / Claude Code

{
  "mcpServers": {
    "zendriver": {
      "command": "uvx",
      "args": ["zendriver-mcp"]
    }
  }
}

No clone, no --directory, no absolute path. If you prefer a permanent install instead, swap "command": "uvx" for "command": "zendriver-mcp" after running uv tool install zendriver-mcp.

Development checkout

Working on zendriver-mcp itself? Clone + uv sync, then point your MCP client at the checkout:

{
  "mcpServers": {
    "zendriver": {
      "command": "uv",
      "args": ["--directory", "/absolute/path/to/zendriver-mcp", "run", "zendriver-mcp"]
    }
  }
}

Optional flags on the CLI:

  • --browser-path /path/to/chrome - point at a specific Chrome binary

  • --transport stdio - only stdio for now; SSE/HTTP arrive when upstream mcp ships stable support

The 30-second tour

# Ask the browser to start, log in once, save the session.
await start_browser()
await navigate("https://example.com/login")
await fill_form({"#email": "me@me.com", "#pw": "..."})
await export_cookies("~/sessions/example.json")

# Next run: skip the login entirely.
await start_browser()
await import_cookies("~/sessions/example.json")
await navigate("https://example.com/dashboard")

# Get an accessibility snapshot, click by stable uid.
snap = await get_accessibility_snapshot()
await click_by_uid("ax_1b2c3d4e")

# Record a performance trace while you click around.
await start_trace()
await human_click(selector="#buy-now")
await stop_trace("/tmp/buy-flow.json")   # loads in Chrome DevTools

# Run Lighthouse against the current browser.
await run_lighthouse("https://example.com", form_factor="mobile")

Token-optimised DOM walker

The interaction tree emits compact rows like {"id": 1, "t": "btn", "l": "Search", "r": "hdr"}:

  • Compact keys: t (type), l (label), r (region)

  • Smart labels: inferred from aria-label, aria-labelledby, associated <label>, placeholder, text, title, alt

  • Noise filtering: SVG internals, nested interactive children skipped

  • Region tagging: hdr, nav, main, side, ftr, dlg

  • Type compression: button -> btn, checkbox -> chk, etc.

Reported reduction on perplexity.ai: ~96% fewer tokens than raw HTML (~11k -> ~400).

For flows that span multiple actions, prefer get_accessibility_snapshot + click_by_uid - the uids stay valid as long as the underlying backend node survives, even across re-renders.

Development

uv sync
uv run ruff check .
uv run ruff format --check .
uv run mypy src
uv run pytest

CI runs the same four on every push and PR.

Roadmap

Everything on the original roadmap shipped in the 0.2 / 0.3 releases:

  • Stealth: Cloudflare solver, UA / locale / timezone / geolocation

  • Human-like input: bezier mouse paths, gaussian keystroke timing

  • DevTools parity: traces, heap snapshots, Lighthouse

  • Screencast + mp4 export via ffmpeg

  • Accessibility tree with stable uids

  • Cookie import/export, blocking, extra headers, permissions

  • Request interception + response mocking (Fetch.enable)

  • Proxy configuration (restart with --proxy-server)

  • ToolResponse envelope adopted in rich-output tools

  • PyPI publish workflow (Trusted Publishing)

Documentation site: https://bituq.github.io/zendriver-mcp/

What's next is driven by actual usage. Ideas on deck:

  • Per-request proxy routing via Fetch interception

  • Binary body support in mock_response

  • Fetch.enable with patterns (faster than our "match all then filter")

License

MIT. See LICENSE.

Acknowledgements

  • Zendriver does the heavy lifting underneath.

  • The token-optimised DOM walker and the original 49-tool foundation come from ShubhamChoulkar/Zendriver-MCP. This project started as a fork and has since grown its own identity and feature set.

Available Tools

98 tools
block_urlsA

Block subsequent requests whose URL matches one of the patterns.

    Patterns use Chrome's wildcard syntax: ``*googletagmanager.com*``,
    ``*.png``, ``https://analytics.example.com/*``. Pass an empty list
    or call ``unblock_all_urls`` to remove all blocks.
    

Inputs: patterns (required). Returns: result

bypass_cloudflareA

Solve a Cloudflare interactive (Turnstile) challenge on the current page.

    Waits up to ``timeout`` seconds for the challenge iframe and then clicks
    the checkbox every ``click_delay`` seconds until the input disappears
    or gets a value. Raises TimeoutError if the challenge cannot be solved
    in time.
    

Inputs: timeout, click_delay. Returns: result

bypass_service_workerC

Skip the service worker and always go to the network.

Inputs: bypass. Returns: result

check_ffmpeg_availableA

Report whether the ffmpeg CLI is installed. Required for export_screencast_mp4.

Inputs: no named parameters. Returns: result

check_lighthouse_availableA

Report whether the lighthouse CLI is installed and its version.

    Use this before ``run_lighthouse`` if you want to prompt the user to
    install it.
    

Inputs: no named parameters. Returns: result

clear_all_cookiesA

Delete every cookie in the current browser context.

Inputs: no named parameters. Returns: result

clear_inputA

Clear an input or contenteditable element via the native setter.

    Uses the same technique React's synthetic-event system expects so
    controlled components actually see the change. Previously we called
    ``document.execCommand`` which is deprecated and invisible to
    React/Vue/Angular state.
    

Inputs: selector (required). Returns: result

clear_logsA

Clear all captured network and console logs.

Inputs: no named parameters. Returns: result

clear_proxyC

Restart the browser without a proxy.

Inputs: headless, user_data_dir. Returns: result

clear_storageA

Clear localStorage and sessionStorage.

Inputs: no named parameters. Returns: result

clear_user_agentA

Remove the override and restore the browser's real User-Agent.

    CDP ``setUserAgentOverride`` has no explicit "clear" command - and
    sending an empty string makes Chrome actually send ``User-Agent:``
    (empty), which is *more* fingerprintable than the real UA. Instead
    we query ``navigator.userAgent`` from a fresh evaluation (Chrome
    returns the real UA there, not the override) and set that back.
    

Inputs: no named parameters. Returns: result

clickA

Click a visible element.

    Accepts a CSS selector, the numeric id from ``get_interaction_tree``
    (e.g. ``"12"`` -> ``[data-zendriver-id="12"]``), or ``text`` to find
    by visible text content.
    

Inputs: text, selector. Returns: result

click_by_uidB

Click the DOM node behind an accessibility uid.

    Resolves the cached ``backend_node_id`` to a remote object, then
    dispatches a native element click. Raises ``AccessibilityUidError``
    if the uid is unknown or the node was removed since the snapshot.
    

Inputs: uid (required). Returns: result

click_shadowA

Click the deepest interactive element inside a custom element's shadow DOM.

    Use when a page wraps a real ``<button>`` / ``[role="radio"]`` /
    ``[role="checkbox"]`` in one or more open shadow roots
    (``<nes-button>``, ``<sds-radio>``, ``<lion-input>`` and friends).
    ``selector`` should match the outer custom element in the light
    DOM; this tool then recurses through every nested ``shadowRoot``
    up to ``max_depth`` levels and dispatches a composed click
    sequence on the first interactive descendant it finds.

    Returns an error when the host isn't found or no inner interactive
    element lives inside its shadow tree.
    

Inputs: selector (required), max_depth. Returns: result

close_tabC

Close a specific tab.

Inputs: tab_id (required). Returns: result

configure_proxyA

Restart the browser so it routes traffic through proxy_url.

    Accepts ``http://host:port``, ``socks5://host:port``, or Chrome's
    full proxy rule syntax. Pass a ``user_data_dir`` to preserve the
    logged-in session across the restart - without it you start fresh.
    

Inputs: proxy_url (required), headless, user_data_dir. Returns: result

describe_shadowA

Dump a custom element's nested shadow-DOM tree for debugging.

    Returns a condensed JSON tree - each node has ``tag``, ``id``,
    ``role``, ``type``, ``text``, a ``light`` array of light-DOM
    children and a ``shadow`` array for the element's shadowRoot
    children (when open). Use this when ``find_buttons`` /
    ``find_inputs`` aren't surfacing a control you can see on the
    page; the result tells you the exact nested-host path so you
    can target ``click_shadow`` or chain custom queries.
    

Inputs: selector (required), max_depth.

describe_uidA

Return the cached role + name for a uid, or raise if unknown.

Inputs: uid (required). Returns: result

emulate_mediaB

Force a CSS media type and/or prefers-color-scheme.

    ``media`` is typically ``""`` (default), ``"screen"``, or ``"print"``.
    ``prefers_color_scheme`` is ``""`` (default), ``"light"``, or ``"dark"``.
    

Inputs: media, prefers_color_scheme. Returns: result

estimated_typing_durationA

Return the expected seconds to type char_count chars at wpm.

    Useful for scheduling follow-up actions without guessing.
    

Inputs: char_count (required), wpm. Returns: result

execute_jsA

Execute JavaScript code on the page and return the result.

    IMPORTANT: Do NOT use 'return' statements directly in your script.
    The script is automatically wrapped to capture the result.

    Examples:
        Good: document.title
        Good: (function() { const x = 1 + 1; return x; })()
        Bad:  return document.title  // SyntaxError!

    For complex scripts, wrap in an IIFE:
        (function() {
            const data = [];
            // ... your code ...
            return data;
        })()
    

Inputs: script (required). Returns: result

export_cookiesA

Dump all cookies to a JSON file.

    Compatible with the "Edit This Cookie" Chrome extension export format
    and Playwright's storage state shape (just the cookies slice).
    Use ``import_cookies`` on another session to restore.
    

Inputs: file_path (required). Returns: result

export_screencast_mp4A

Stitch screencast frames in frames_dir into an mp4.

    Uses the default ``frame-%06d.jpg`` / ``frame-%06d.png`` pattern that
    ``start_screencast`` writes. ``fps`` is the playback rate (not the
    capture rate). Requires ffmpeg.
    

Inputs: frames_dir (required), fps, output_path. Returns: result

fail_requestsA

Fail every request matching url_pattern with error_reason.

    ``error_reason`` must match a CDP ``Network.ErrorReason`` member
    (``Failed``, ``Aborted``, ``TimedOut``, ``AccessDenied``,
    ``ConnectionClosed``, ``ConnectionReset``, ``ConnectionRefused``,
    ``ConnectionAborted``, ``ConnectionFailed``, ``NameNotResolved``,
    ``InternetDisconnected``, ``AddressUnreachable``, ``BlockedByClient``,
    ``BlockedByResponse``).
    

Inputs: url_pattern (required), error_reason. Returns: result

fill_formA

Fill multiple form fields. Pass JSON like {"#email": "x@y.com"}.

    Reports which selectors succeeded and which were missing so the
    caller can tell partial fills from full ones. Fields are cleared
    before typing so values don't concatenate with existing content.
    

Inputs: form_data (required). Returns: result

find_all_elementsA

Find all elements matching a selector. Returns quickly on no match.

    ``limit`` caps the number of summary rows; the total count is always
    accurate. Zendriver's ``select_all`` raises ``TimeoutError`` after
    ~10s on zero matches, which we catch and translate to a clean
    "no elements found" message.
    

Inputs: selector (required), limit. Returns: result

find_buttonsA

Find all clickable elements on the page - including shadow DOM.

    Walks both the light DOM and every open shadow root, so buttons
    hidden inside custom elements like ``<nes-button>`` or
    ``<sds-cta>`` show up. Recognises native tags (button, a, input,
    summary) plus ARIA roles (button, link, checkbox, radio, switch,
    menuitem, tab, option, treeitem) and cursor=pointer elements
    with an onclick handler. Each entry shows the host's CSS
    selector; for shadow-wrapped buttons use ``click_shadow`` to
    reach the inner interactive element.
    

Inputs: filter_text. Returns: result

find_elementC

Find an element and return information about it.

Provides helpful suggestions if element is not found.

Inputs: text, selector. Returns: result

find_inputsA

Find all input fields on the page - including shadow DOM.

    Walks both the light DOM and every open shadow root. Recognises
    ``<input>``, ``<textarea>``, ``role=textbox/searchbox/combobox``,
    ``[contenteditable="true"]`` and custom elements whose tag name
    suggests an input (contains "input" or "field"). ``filter_type``
    is a case-insensitive substring match against the input's type
    attribute or ARIA role.
    

Inputs: filter_type. Returns: result

focus_elementC

Focus on an element.

Inputs: selector (required). Returns: result

get_accessibility_snapshotA

Return the page's accessibility tree with stable uids.

    Each node looks like ``{"uid": "ax_1b2c", "role": "button",
    "name": "Submit", "children": [...]}``. The uid can be passed to
    ``click_by_uid`` for deterministic interaction.

    - ``max_nodes``: cap the node count to keep the response small.
    - ``interesting_only``: skip ignored/structural nodes (``none``,
      ``generic``, ``InlineTextBox``, ``StaticText``) while keeping
      their children, so the tree stays compact without losing content.
    

Inputs: max_nodes, interesting_only. Returns: result

get_browser_statusA

Return browser running state plus a list of open tabs.

Inputs: no named parameters. Returns: object

get_console_logsC

Get recent console logs captured via CDP.

Inputs: limit. Returns: result

get_contentB

Get the page HTML, max_chars chars from offset.

    The first line reports the slice, total size, and the next offset
    when more content is available.
    

Inputs: offset, max_chars. Returns: result

get_cookiesA

Read document.cookie for the current origin only.

    Intentionally limited: HTTP-only and other-origin cookies are
    invisible here. For full-fidelity cookie access use
    ``list_all_cookies`` / ``export_cookies`` from the ``cookies``
    module instead.
    

Inputs: no named parameters. Returns: result

get_element_attributeC

Get an attribute value from an element.

Inputs: selector (required), attribute (required). Returns: result

get_element_textC

Get the text content of an element.

Inputs: selector (required). Returns: result

get_interaction_treeA

List interactive elements as compact JSON with numeric ids.

    The ids double as selectors for click/type tools. ``limit`` caps
    the element count.
    

Inputs: limit. Returns: result

get_local_storageA

Get all localStorage items.

Inputs: no named parameters. Returns: result

get_network_logsB

Get recent network request logs captured via CDP.

Inputs: limit. Returns: result

get_page_infoA

Return the current tab's URL and title.

    Reads ``document.title`` and ``location.href`` via ``page.evaluate``
    instead of trusting zendriver's cached ``tab.target`` metadata,
    which can be stale right after navigation - and on some zendriver
    versions ``tab.title`` is a coroutine method, so ``getattr`` would
    return the bound method repr string.
    

Inputs: no named parameters. Returns: object

get_text_contentC

Get visible page text; same pagination contract as get_content.

Inputs: offset, max_chars. Returns: result

go_backA

Navigate back in browser history.

Inputs: no named parameters. Returns: result

go_forwardA

Navigate forward in browser history.

Inputs: no named parameters. Returns: result

grant_permissionsB

Grant permissions to origin (or all origins if omitted).

    Accepted names are listed by ``list_permission_names``. Any name
    that resolves to a full CDP enum key is also accepted (e.g.
    ``VIDEO_CAPTURE`` or ``videoCapture``).
    

Inputs: permissions (required), origin. Returns: result

human_clickA

Click an element with a humanish cursor path.

    Accepts a CSS selector, the numeric ID from ``get_interaction_tree``,
    or visible text. ``move_duration`` is how long the mouse takes to
    reach the target (default 0.4s). Text-mode is shadow-DOM aware:
    the walker finds the tightest interactive element matching the
    text (descending into nested shadowRoots when needed) and aims
    the cursor at its composed viewport rect, so clicks land on the
    real handler inside custom elements like ``<nes-button>``.
    

Inputs: text, selector, move_duration. Returns: result

human_typeA

Type text with per-keystroke delays modelling wpm.

    If ``selector`` is provided the element is focused first via a
    human click. 220 wpm is a fast but plausible adult typist.
    

Inputs: text (required), wpm, selector. Returns: result

import_cookiesA

Load cookies from a JSON file produced by export_cookies.

    Silently skips entries that fail the ``CookieParam`` schema so a
    partial restore still works. Existing cookies with the same
    (name, domain, path) triple are overwritten by Chrome.
    

Inputs: file_path (required). Returns: result

is_cloudflare_challenge_presentA

Report whether a Cloudflare interactive challenge is visible.

    Fast probe - use before ``bypass_cloudflare`` to skip the click cycle
    when the page already passed.
    

Inputs: timeout. Returns: result

list_all_cookiesA

Return every cookie the browser is holding, across all origins.

Inputs: no named parameters. Returns: result

list_devicesA

Return the list of available device profile keys.

Inputs: no named parameters. Returns: result

list_interceptionsB

Return the active interception rules with their match counts.

Inputs: no named parameters. Returns: result

list_network_profilesA

Return the mapping of profile name -> CDP parameters.

Inputs: no named parameters. Returns: result

list_permission_namesA

Return the short permission names we accept in grant_permissions.

Inputs: no named parameters. Returns: result

list_tabsA

List all open tabs with their URLs.

Inputs: no named parameters. Returns: object

mock_responseA

Return a mocked response for every request matching url_pattern.

    ``url_pattern`` uses Unix glob syntax (``*``, ``?``), matched against
    the full request URL. ``body`` is UTF-8 text (cap: 10 MiB to prevent
    RAM exhaustion). Returns a rule id; pass it to
    ``stop_interception(rule_id)`` or call with no args to clear all.
    

Inputs: url_pattern (required), body, status, headers. Returns: result

mouse_clickC

Click at specific coordinates.

Inputs: x (required), y (required). Returns: result

new_tabC

Open a new browser tab.

Inputs: url. Returns: result

press_enterA

Press Enter key - convenience wrapper for press_key('Enter').

Inputs: selector. Returns: result

press_keyA

Press a keyboard key via CDP Input.dispatchKeyEvent.

    Uses real browser key events, not synthetic JS dispatch - so native
    form-submit semantics, browser shortcuts, and IME all behave as
    they would with a human keyboard. When ``selector`` is given we
    focus that element first.

    Recognised names: ``Enter``, ``Tab``, ``Escape``, ``Backspace``,
    ``Delete``, ``ArrowUp/Down/Left/Right``, ``Space``, ``Home``, ``End``,
    ``PageUp``, ``PageDown``. Any single character (e.g. ``"a"``) is also
    accepted.
    

Inputs: key (required), selector. Returns: result

reload_pageA

Reload the current page.

Inputs: no named parameters. Returns: result

reset_permissionsA

Reset every permission override in the current browser context.

Inputs: no named parameters. Returns: result

restore_viewportA

Restore the real device's viewport by clearing the override.

Inputs: no named parameters. Returns: result

run_lighthouseA

Audit url with Lighthouse and return scores + report path.

    - ``categories``: subset of ``performance``, ``accessibility``,
      ``best-practices``, ``seo``, ``pwa``. Defaults to the first four.
    - ``form_factor``: ``"mobile"`` or ``"desktop"``.
    - ``output_path``: where to save the JSON report. Empty => temp file.

    The browser must have been started with remote-debugging exposed,
    which zendriver does by default.
    

Inputs: url (required), categories, form_factor, output_path. Returns: result

run_security_auditA

Run a comprehensive security audit on the current page.

    Checks for: HTTPS, CSRF protection, password security, mixed content,
    inline scripts, SRI (Subresource Integrity), forms, sensitive data exposure,
    and JavaScript security patterns.
    

Inputs: no named parameters. Returns: result

screenshotA

Screenshot the page as JPEG, downscaled to max 1024px wide.

    Args:
        save_path: Optional path to also save to disk at full
            resolution (format from the extension).
        full_resolution: Return the image without downscaling.
    

Inputs: save_path, full_resolution.

scrollA

Scroll the page up or down by pixels (instant, not animated).

    Uses JavaScript ``window.scrollBy`` directly. The earlier implementation
    called zendriver's ``scroll_down`` which interprets its argument as a
    *percentage* of the viewport and animates via
    ``Input.synthesizeScrollGesture`` - turning e.g. 500 into five
    viewport-heights of smooth scrolling.
    

Inputs: pixels, direction. Returns: result

scroll_to_elementA

Scroll to bring an element into view, or raise if it's missing.

    Honest success / failure reporting: if no element matches the
    selector we raise ``ElementNotFoundError`` instead of silently
    no-op'ing with a fake "Scrolled to: ..." message.
    

Inputs: selector (required). Returns: result

select_optionC

Select an option from a dropdown.

Inputs: value (required), selector (required). Returns: result

set_cpu_throttleA

Slow the CPU by a multiplier.

    ``1.0`` disables throttling, ``4.0`` is DevTools' "4x slowdown",
    ``20.0`` roughly emulates a low-end phone.
    

Inputs: rate. Returns: result

set_deviceA

Emulate a preset device.

    Call ``list_devices`` to see available profile keys
    (e.g. ``iphone-15-pro``, ``pixel-8``, ``ipad-pro``, ``desktop-1080p``).
    Also sets a matching User-Agent when the profile provides one.
    

Inputs: profile (required). Returns: result

set_extra_headersA

Add headers to every outgoing request on the current tab.

Useful for API keys, tenant overrides, tracing ids. Pass an empty dict to clear.

Inputs: headers (required). Returns: result

set_geolocationC

Override the browser's geolocation. Accuracy is in metres.

Inputs: latitude (required), longitude (required), accuracy. Returns: result

set_localeA

Override the browser locale (ICU C-style, e.g. nl_NL, en_US).

    Affects navigator.language, Intl APIs, and Accept-Language defaults.
    Pass an empty string to restore the system locale.
    

Inputs: locale (required). Returns: result

set_local_storageC

Set a localStorage item.

Inputs: key (required), value (required). Returns: result

set_network_conditionsA

Apply a named network-throttling preset.

    Options: ``offline``, ``slow-3g``, ``fast-3g``, ``4g``,
    ``no-throttling``. See ``list_network_profiles`` for the numeric
    values.
    

Inputs: profile (required). Returns: result

set_timezoneA

Override the IANA timezone (e.g. Europe/Amsterdam, America/New_York).

    Pass an empty string to restore the system timezone.
    

Inputs: timezone_id (required). Returns: result

set_user_agentA

Override User-Agent, Accept-Language, and navigator.platform.

    Applies to every subsequent request on the current tab until
    ``clear_user_agent`` is called or the tab closes. ``platform`` should
    match the UA (e.g. ``"Win32"`` for a Windows UA).
    

Inputs: user_agent (required), platform, accept_language. Returns: result

set_viewportA

Override the visible viewport dimensions.

    ``width`` / ``height`` in CSS pixels. ``device_scale_factor`` is DPR
    (1.0 for standard, 2.0 for Retina, etc.). ``mobile`` toggles the
    meta-viewport / overlay-scrollbar behaviour.
    

Inputs: width (required), height (required), mobile, device_scale_factor. Returns: result

start_browserC

Start the browser with configuration options.

Inputs: proxy, headless, user_data_dir. Returns: result

start_screencastB

Begin recording screencast frames to output_dir.

    - ``fmt``: ``"jpeg"`` (smaller) or ``"png"`` (lossless).
    - ``quality``: 0-100, JPEG only.
    - ``max_width``: frames are downscaled to this width if larger.
    - ``every_nth_frame``: skip frames between captures (1 = every frame).
    

Inputs: fmt, quality, max_width, output_dir, +1 more. Returns: result

start_traceA

Begin recording a performance trace on the current tab.

    ``categories`` is a comma-separated CDP category filter; empty string
    uses the DevTools Performance-panel default profile. Only one trace
    can be active per tool instance at a time.
    

Inputs: categories. Returns: result

stop_browserA

Stop the browser and clean up all resources.

Inputs: no named parameters. Returns: result

stop_interceptionA

Remove one rule by id, or all rules when rule_id is omitted.

Inputs: rule_id. Returns: result

stop_screencastA

Stop the active screencast and return the frame directory + count.

Inputs: no named parameters. Returns: result

stop_traceA

Stop the active trace and write it to disk as JSON.

    Returns the absolute file path. If ``file_path`` is empty, writes to
    a timestamped file in the system temp directory. The output matches
    the format that Chrome DevTools' "Load profile" accepts.

    Handlers and state are cleared via ``finally`` so a failed
    ``tracing.end()`` or a late ``tracingComplete`` never leaves the
    tool stuck on "a trace is already in progress" for the rest of the
    process.
    

Inputs: file_path. Returns: result

submit_formA

Submit a form, honouring framework-level submit listeners.

    Uses ``form.requestSubmit()`` so React/Vue/Formik ``onSubmit``
    handlers fire and HTML validation runs, falling back to a bubbling
    ``submit`` event and finally ``form.submit()`` for ancient pages.
    Returns an error if the selector matches no form.
    

Inputs: selector. Returns: result

switch_tabB

Switch to a specific tab.

Inputs: tab_id (required). Returns: result

take_heap_snapshotB

Capture a V8 heap snapshot and write it to disk.

    The output is the same ``.heapsnapshot`` format Chrome DevTools saves,
    loadable via DevTools > Memory > Load.
    

Inputs: file_path. Returns: result

type_textA

Focus an element and type text via CDP Input.insertText.

    By default the field is cleared first (``replace=True``). Set
    ``replace=False`` to append to the existing value.
    

Inputs: text (required), selector (required), replace. Returns: result

unblock_all_urlsA

Remove every URL-pattern block.

Inputs: no named parameters. Returns: result

upload_fileC

Upload a file to a file input.

Inputs: selector (required), file_path (required). Returns: result

waitB

Wait for specified seconds.

Inputs: seconds. Returns: result

wait_for_elementA

Wait for an element to appear on the page.

    Args:
        selector: CSS selector to wait for
        timeout: Maximum time to wait in seconds (default: 30s for SPAs)
        visible: If True, also checks element is visible (not hidden)
    

Inputs: selector (required), timeout, visible. Returns: result

wait_for_networkA

Wait for network activity to become idle.

    Useful after triggering actions that cause API calls.

    Args:
        timeout: Maximum time to wait in seconds
        idle_time: How long network must be idle to consider it done
    

Inputs: timeout, idle_time. Returns: result

wait_for_requestB

Wait for a matching request to complete (response received).

    Only log entries with a resolved status code are considered, so this
    returns after the server replied, not the moment Chrome sent the
    request. ``url_pattern`` is a case-insensitive substring of the full
    URL; ``method`` optionally filters on HTTP verb.
    

Inputs: url_pattern (required), method, timeout. Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.3/5.0

    Scored across 98 tools

    Disambiguation4/5

    Most tools have clearly distinct purposes, but the proliferation of multiple click (click, human_click, click_shadow, mouse_click, click_by_uid) and type (type_text, human_type, clear_input, fill_form) methods could cause some confusion despite good descriptions.

    Naming Consistency4/5

    Naming follows a consistent verb_noun snake_case pattern overall, with minor variations like 'human_click' vs 'click' and some phrasal verbs (wait_for, scroll_to). No mixed conventions or chaotic patterns.

    Tool Count2/5

    98 tools is far beyond the 25+ threshold considered excessive in the calibration. While many are justified by the comprehensive scope of browser automation, the sheer number likely overwhelms agents and makes selection difficult.

    Completeness5/5

    The tool set covers virtually every aspect of browser automation: navigation, element interaction, cookies/storage, emulation, performance tracing, security auditing, accessibility, network interception, and more. There are no apparent gaps for the intended domain.

    Maintenance

    ActivityInactive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers