zendriver-mcp
Provides Cloudflare Turnstile solver to bypass anti-bot challenges, enabling undetectable browsing on sites protected by Cloudflare.
Allows exporting screencast frame sequences to MP4 video files via FFmpeg, enabling recording of browser sessions.
Enables running Lighthouse audits (performance, accessibility, SEO) against the current page or a specified URL, using the undetectable browser.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@zendriver-mcp Go to example.com, log in, and export cookies"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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
.heapsnapshotformat, 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 |
| start, stop, status |
| navigate, back, forward, reload, page info |
| new / list / switch / close |
| click, type, clear, focus, select, upload |
| find element(s), text, attributes, buttons, inputs |
| HTML, text, interaction tree, scroll |
| cookies (document.cookie), localStorage |
| network + console logs, wait-for-request |
| fill form, submit, key press, mouse click |
| screenshot, execute JS, wait, security audit |
| Cloudflare bypass, UA / locale / timezone / geolocation overrides |
| human_click, human_type, estimated_typing_duration |
| viewport, device presets, CPU + network throttle, media |
| start/stop trace, take heap snapshot |
| run audit, check CLI availability |
| start / stop (writes frame directory) |
| AX snapshot with stable uids, click_by_uid, describe_uid |
| export / import / list / clear (CDP-level, all origins) |
| block URLs, extra headers, bypass service worker |
| grant / reset, list names |
| configure / clear (restarts browser with proxy args) |
| mock_response, fail_requests, list, stop |
| + 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-mcpUse 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 upstreammcpships 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,altNoise filtering: SVG internals, nested interactive children skipped
Region tagging:
hdr,nav,main,side,ftr,dlgType 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 pytestCI 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)ToolResponseenvelope adopted in rich-output toolsPyPI 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_responseFetch.enablewith 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 toolsblock_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_cookieA
Set a cookie via document.cookie (limited to current origin).
Cannot set HTTP-only or cross-origin cookies. Prefer
``import_cookies`` for restoring full sessions across origins.
Inputs: name (required), value (required), domain. 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
Scored across 98 tools
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 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.
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.
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
Related MCP Connectors
Web scraping, browser automation, screenshots and AI data extraction for AI agents via MCP.
Stealth web automation for AI agents. Login, signup, navigate, screenshot.
Stealth web automation for AI agents. Login, signup, navigate, screenshot.
Official Browserless MCP server: browser automation, scraping, screenshots and PDFs for AI agents.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceProvides a real browser that bypasses bot detection (Cloudflare, Turnstile) for AI agents, enabling navigation, clicking, typing, screenshots, and data collection through MCP tools.166 npmMIT
- AlicenseNot gradedqualityDmaintenanceA browser automation MCP server with stealth mode, profile management, and multi-browser support, enabling LLMs to control browsers for tasks like navigation, data extraction, and form filling.11 npm1MIT
- AlicenseAqualityCmaintenanceA lightweight, stealthy headless browser for AI agents, providing MCP tools for web extraction, interaction, and snapshotting.122Apache 2.0
- AlicenseBqualityBmaintenanceEnables AI agents to control a stealth Patchright-driven browser via MCP, automating complex web tasks while evading anti-bot systems like Cloudflare, Akamai, Kasada, and DataDome.66135 npm1MIT