Skip to content
verify mcp Beta VerifyMCP is currently in beta. If you notice any issues, get in touch and we’ll put it right.

nodriver — undetected browser automation

PYPI · NODRIVER-MCP · SCANNED SEP 21

Undetected anti-bot Chrome automation. 65 tools, parallel isolated browsers.

Available components

0 this week 65 Trust /100
Trust breakdown (7 categories)

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. How we score → Why this is hard to score →

Supply Chain Security50
  • Malware scan not yet available for this package.Unverified
  • No known CVEs affecting this package version or its production dependencies.Pass
  • Runs setuptools.build_meta at install time, a recognised native-build step with no shell scripting around it. View diagnostics → Pass
  • 1 of 37 dependencies flagged as unhealthy. View diagnostics → Partial
Provenance & Transparency32
Schema Quality & AI Usability67
  • AI-judged instruction clarity (excellent).Pass
  • Context-footprint check failed: tool/resource definitions use about 17117 tokens (~263/item across 65 items; 65 tools + 0 resources), over budget; trim descriptions and params. See how to fix → Fail
  • Usage-examples check failed: none of the tools include examples. See how to fix → Fail
Stability & Change Management97
  • Stability observed for 29 of 30 days with no destabilising changes; credit accrues until the full window elapses.Partial
Tool Coverage100
  • 100% of tools have a non-trivial description (not blank, and not just the tool's name).Pass
  • 100% of tool parameters carry a description.Pass
  • Structured output schemas are declared (97% of tools); any adoption earns full credit.Pass
Tool Safety100
  • No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.Pass
  • All 5 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation.Pass
  • An AI judge read all 66 captured unit(s) of tool text and found none that tries to manipulate the model reading it.Pass
Capabilities100
  • Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.Pass
Install

How do I install the nodriver — undetected browser automation MCP server?

nodriver — undetected browser automation runs locally as a PyPI package, launched with uvx nodriver-mcp. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

pypi · nodriver-mcp

# add to Claude Code
claude mcp add andresolbach-nodriver-mcp-server -- uvx nodriver-mcp
// .cursor/mcp.json
{
  "mcpServers": {
    "andresolbach-nodriver-mcp-server": {
      "command": "uvx",
      "args": [
        "nodriver-mcp"
      ]
    }
  }
}
// .vscode/mcp.json
{
  "servers": {
    "andresolbach-nodriver-mcp-server": {
      "command": "uvx",
      "args": [
        "nodriver-mcp"
      ]
    }
  }
}
# add to Codex CLI
codex mcp add andresolbach-nodriver-mcp-server -- uvx nodriver-mcp
// opencode.json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "andresolbach-nodriver-mcp-server": {
      "type": "local",
      "command": [
        "uvx",
        "nodriver-mcp"
      ],
      "enabled": true
    }
  }
}
# add to OpenClaw
openclaw mcp add andresolbach-nodriver-mcp-server --command uvx --arg nodriver-mcp
# ~/.hermes/config.yaml
mcp_servers:
  andresolbach-nodriver-mcp-server:
    command: "uvx"
    args: ["nodriver-mcp"]
// ~/.netclaw/config/netclaw.json
{
  "McpServers": {
    "andresolbach-nodriver-mcp-server": {
      "Transport": "stdio",
      "Command": "uvx",
      "Arguments": [
        "nodriver-mcp"
      ]
    }
  }
}
# add to Vellum
assistant mcp add andresolbach-nodriver-mcp-server -t stdio -c uvx -a nodriver-mcp
// mcp.json
{
  "mcpServers": {
    "andresolbach-nodriver-mcp-server": {
      "command": "uvx",
      "args": [
        "nodriver-mcp"
      ]
    }
  }
}
Changelog

Every change we have recorded for this component, newest first. Security-relevant changes are always shown. ▲ marks a change for the better, ▼ a change for the worse; unmarked changes are neutral.

  • 21 Sept 26 +1

    No change was recorded against any check on this day. Stability & Change Management went from 93 to 97. That category is still filling its 30-day observation window: 28 days of observed history at the previous scan, 29 at this one. The score rises as the window fills, whether or not the server changes.

  • 18 Sept 26 +1

    No change was recorded against any check on this day. Stability & Change Management went from 83 to 87. That category is still filling its 30-day observation window: 25 days of observed history at the previous scan, 26 at this one. The score rises as the window fills, whether or not the server changes.

  • 16 Sept 26 −2
    • Stability: pass → 0.80 functional
  • 15 Sept 26 0
    • Stability: 0.97 → pass security
  • 14 Sept 26 −14
    • Malware scan: pass → unverified security
  • 13 Sept 26 +15
    • Malware scan: unverified → pass security
  • 11 Sept 26 −14
    • Malware scan: pass → unverified security
  • 9 Sept 26 +1
    • Security disclosure: unverified → fail functional
Diagnostics

Diagnostic detail from the automated scan of this channel: what the scanner observed at each step, so you can see exactly where a check passed or failed. It is informational only and never changes the trust score.

Captured 21 Sept 2026 · Analysed pypi/nodriver-mcp@2.4.0

Provenance No attestation

The registry publishes no build provenance for this version, so there is nothing to verify.

Result No attestation
Ecosystem pypi

Background: How many MCP packages publish verified provenance →

Install scripts 1 script
Hook Tier Command
build_backend allowlisted setuptools.build_meta

Background: Why install scripts are a supply-chain risk →

Dependencies 37 packages
Packages resolved 37
Stale 1
Tree resolution Complete

Background: SBOMs and build attestations, explained →

MCP tools · 65 exposed · ~16,297 tokens

The tools this component advertises to a client, with an estimated token cost for each. Expand a tool to see its parameters and schema. The per-tool counts are indicative and are not scored directly; the schema's total context footprint is one signal in Schema Quality & AI Usability. A tool's description is untrusted text the model reads on every call, which is what makes this list a security surface and not just an inventory: how tool poisoning works →

Tool Tokens
block_resources ~260

Block images, fonts, stylesheets or media to speed up page loads. Removes most of the bytes on a media-heavy page, which makes scraping several times faster and far cheaper over a metered or proxied connection. Blocking stylesheets breaks layout, so anything that depends on element geometry becomes unreliable — click_at, element screenshots, and the `visible` check in wait_for_selector. Text extraction is unaffected. Requests are matched on the resource type Chrome reports for them, so an asset served from an extension-less URL is still blocked, and blocking one type never catches another. Applies to ONE TAB — the selected page — and stays in effect there across navigations until called again with no types. A tab opened afterwards with new_page starts unblocked and needs its own call.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
typesResource types to block. ["image", "font", "media"] is the usual choice for scraping — it keeps stylesheets, so layout-dependent behaviour still works. Pass an empty list or omit to unblock everythin…
NameTypeReqDescription
resultstringyes

No examples provided.

bypass_insecure_warning ~127

Click through Chrome's "Your connection is not private" interstitial. Use this when a navigation lands on an SSL/certificate warning page (expired or self-signed certificate, hostname mismatch) instead of the site itself — the snapshot then shows a warning page rather than the expected content. This performs the Advanced -> Proceed click for you. Has no effect on any other kind of page.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
NameTypeReqDescription
resultstringyes

No examples provided.

cf_verify ~184

Attempt to solve a Cloudflare "Verify you are human" challenge. Use when a page is stuck on a Cloudflare interstitial — a checkbox widget, or "Checking your browser before accessing". Drives nodriver's built-in verification bypass, which locates the checkbox visually and clicks it. Needs opencv, which is an optional extra: install nodriver-mcp[cf], or this reports that it is missing rather than failing obscurely. Many challenges clear by themselves after a few seconds, so wait_for(["some text from the real page"]) is worth trying first — and this says so when it looks at the page and finds no challenge at all.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
NameTypeReqDescription
resultstringyes

No examples provided.

clear_cookies ~129

Delete every cookie in the browser. Browser-wide, not per site and not per tab — this logs you out of everything at once, with no undo. Restore a previous state with load_session if you have one saved. Useful for testing a first-time-visitor flow or resetting a consent banner decision. localStorage is left untouched, so sites that keep state there may still recognise you.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
NameTypeReqDescription
resultstringyes

No examples provided.

click ~547

Click an element addressed by its snapshot uid. This is the click you want in almost all cases — prefer it over click_at, because a uid survives layout shifts and raw coordinates do not. The element is scrolled into view first, so it need not be visible beforehand. Sends real CDP input events, so the page sees `isTrusted=true`, which is the entire point of an undetected driver. Because those are delivered by coordinate, the click is aimed at a point that actually hits the element: several points inside it are hit-tested first, since a sticky header or a banner can cover the centre. If none of them reach it, `if_covered` decides what happens, and the response always says which path was taken. Two other situations force the scripted fallback regardless: a touch-emulated target, where CDP mouse input can crash the renderer, and a CDP click that times out or errors. Every step is bounded at 10s, so a wedged page cannot hang the call. On "unknown uid", take a fresh take_snapshot and retry with the new uid.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
dbl_clickbooleanSend a double-click instead of a single click.
if_coveredstringWhat to do when something else sits on top of the element, so a real mouse click at its position would hit that instead. "report" (the default) does not click at all: it returns an error naming what…
include_snapshotbooleanAppend a fresh page snapshot to the response. Worth it when this action changes the page and take_snapshot would be your next call anyway — it saves a round trip, at the cost of a much larger respons…
uidstringyesElement uid from the most recent take_snapshot, e.g. "4_12". uids are invalidated whenever the page changes — if you get "unknown uid", take a fresh snapshot and retry with the new uid.
NameTypeReqDescription
resultstringyes

No examples provided.

click_at ~289

Click a raw viewport coordinate instead of an element. Use `click` with a uid whenever the target shows up in a snapshot — it is robust against layout shifts, this is not. Coordinates are for surfaces with no addressable element: canvases, maps, video players, image hotspots. The point must lie inside the current viewport; scroll_page or scroll_to_selector first if it does not. Coordinates are in CSS pixels and ignore the device pixel ratio, so they match what emulate/resize_page report. Same input path as `click`: real CDP events, the same reported scripted fallback, the same 10s bound per step.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
dbl_clickbooleanSend a double-click instead of a single click.
include_snapshotbooleanAppend a fresh page snapshot to the response. Worth it when this action changes the page and take_snapshot would be your next call anyway — it saves a round trip, at the cost of a much larger respons…
xintegeryesX coordinate in CSS pixels, relative to the viewport's top-left corner.
yintegeryesY coordinate in CSS pixels, relative to the viewport's top-left corner.
NameTypeReqDescription
resultstringyes

No examples provided.

close_browser ~203

Quit Chrome entirely, closing every tab. Unlike close_page (which always keeps one tab alive), this tears down the whole browser. Chrome relaunches automatically on the next tool call with the currently selected profile, so this is also how you apply pending launch flags without switching profiles. On an ephemeral temp profile (the default) this discards cookies, logins and localStorage — save_session first if you need them back. Persistent profiles created with create_profile keep everything. It keeps the browser itself. The name, its selected profile and its launch flags survive for the next relaunch, so the name goes on counting against the 12-browser limit. When an agent is finished for good, call shutdown_browser instead: it also releases the name.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
NameTypeReqDescription
resultstringyes

No examples provided.

close_page ~151

Close a single browser tab. The last remaining tab cannot be closed — use close_browser to shut Chrome down entirely. Closing the selected page clears the selection, so subsequent tools fall back to the most recently opened tab. Returns the remaining open pages, because indices shift when a tab closes: re-read them from this response rather than reusing older ones.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
page_idintegerIndex of the page to close, as listed by list_pages. -1 (the default) closes the currently selected page.
NameTypeReqDescription
resultstringyes

No examples provided.

create_profile ~243

Create a named persistent Chrome profile — a reusable user-data dir. A persistent profile keeps cookies, logins and Web Store extensions between runs, so a site you log into once stays logged in. It is the sturdier alternative to save_session / load_session. Creating one is harmless by itself: nothing changes until you activate it, here or via use_profile. An existing profile of the same name is left untouched rather than overwritten. Profiles live under ~/.nodriver-mcp/profiles/<name>. Only one browser instance can use a given profile at a time, so give concurrent setups different names.

NameTypeReqDescription
activatebooleanSwitch to the new profile straight away. That restarts the browser and closes all open pages. Default false, which only creates the directory.
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
namestringyesProfile name, e.g. "google-login". Only letters, digits, "-" and "_" are kept; any other character is stripped out.
NameTypeReqDescription
resultstringyes

No examples provided.

delete_profile ~118

Permanently delete a persistent Chrome profile directory. Irreversible: the profile's cookies, logins, history and installed extensions are removed from disk, with no undo. The active profile cannot be deleted — switch away with use_temp_profile first.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
namestringyesName of the persistent profile to delete, as shown by list_profiles.
NameTypeReqDescription
resultstringyes

No examples provided.

disable_console_collection ~111

Stop capturing console output on the current page. Turns the CDP Runtime domain back off, which restores the quieter, harder-to-detect default — worth doing once you are finished debugging and the page still has anti-bot checks ahead of it. Messages already collected stay readable; only new ones stop arriving.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
NameTypeReqDescription
resultstringyes

No examples provided.

drag ~246

Drag one element onto another (press, move, release). Both uids must come from the same take_snapshot. Both ends are scrolled into view and hit-tested first, and the pointer is moved in steps with the button held, which is what mouse-driven sortables and sliders listen for. This drives the mouse. Native HTML5 drag-and-drop — the dataTransfer kind — is a separate protocol that a synthetic mouse does not trigger in Chrome; if nothing happens on a page that uses it, that is why.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
from_uidstringyesuid of the element to pick up, from the most recent take_snapshot.
include_snapshotbooleanAppend a fresh page snapshot to the response. Worth it when this action changes the page and take_snapshot would be your next call anyway — it saves a round trip, at the cost of a much larger respons…
to_uidstringyesuid of the element to drop onto, from the most recent take_snapshot.
NameTypeReqDescription
resultstringyes

No examples provided.

emulate ~618

Emulate network, CPU, geolocation, user agent, color scheme or viewport. Applies to the selected page and persists across navigations until reset_emulation. Every parameter is independent — pass only what you want to change, leave the rest at their defaults. Settings already in force are carried over rather than dropped: a user_agent on its own keeps the client hints a device preset established, and a viewport on its own keeps its touch and mobile flags unless you clear them with `notouch` / `nomobile`. To emulate a real phone or tablet, use emulate_device instead: it sets user agent, client hints, viewport, DPR and touch as one coherent set, which hand-assembled overrides here get wrong in ways anti-bot systems detect. Turning `touch` on in the viewport also changes how `click` behaves — CDP mouse input can crash a touch-emulated renderer, so clicks fall back to the scripted path (`isTrusted=false`) for as long as touch is enabled.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
color_schemestringEmulate the prefers-color-scheme media feature. "auto" clears a previous override; empty string leaves it unchanged.
cpu_throttling_ratenumberSlow the CPU by this factor to emulate a low-end device (4 = 4x slower; 1-20 is the useful range). 0 or 1 means no throttling.
geolocationOverride geolocation, as "latitude,longitude" (e.g. "37.7749,-122.4194"). Omit to leave unchanged; pass an empty string to clear a previous override.
network_conditionsstringThrottle the network to a preset profile. "Offline" cuts the connection entirely. Empty string leaves throttling unchanged.
user_agentOverride the User-Agent header and navigator.userAgent. Omit to leave unchanged; pass an empty string to restore Chrome's real one. This does NOT touch UA client hints (Sec-CH-UA-*), which then contr…
viewportstringViewport override as "WIDTHxHEIGHTxDPR[,mobile][,touch][,landscape]", e.g. "375x812x3,mobile,touch" or "1920x1080x1". The trailing flags are optional: `mobile` turns on mobile viewport behaviour, `to…
NameTypeReqDescription
resultstringyes

No examples provided.

emulate_device ~471

Emulate a phone or tablet with one internally consistent set of signals. Preferred over assembling `emulate` parameters by hand for mobile work: user agent, UA client hints (Sec-CH-UA-*), viewport, device pixel ratio, touch support and Accept-Language are set together so they cannot contradict each other — a mismatch between them is a classic automation tell. Presets are pixel_7, pixel_7_landscape and ipad_air (aliases are listed in the `device` parameter). ipad_air deliberately reports desktop-class Safari with touch and sends no client hints, which is what a real iPad does. Applies to the selected page and survives navigation. To have mobile signals present on a page's very first request, pass `device` to new_page or navigate_page instead of calling this afterwards. Undo with reset_emulation.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
color_schemestringEmulate the prefers-color-scheme media feature. "auto" clears a previous override; empty string leaves it unchanged.
cpu_throttling_ratenumberSlow the CPU by this factor to emulate a low-end device (4 = 4x slower; 1-20 is the useful range). 0 or 1 means no throttling.
devicestringyesDevice to emulate — sets user agent, UA client hints, viewport, device pixel ratio and touch together. Presets: "pixel_7" (aliases: pixel7, android, android_phone), "pixel_7_landscape" (pixel7_landsc…
geolocationOverride geolocation, as "latitude,longitude" (e.g. "37.7749,-122.4194"). Omit to leave unchanged; pass an empty string to clear a previous override.
network_conditionsstringThrottle the network to a preset profile. "Offline" cuts the connection entirely. Empty string leaves throttling unchanged.
NameTypeReqDescription
resultstringyes

No examples provided.

enable_console_collection ~158

Start capturing console output on the current page. Call this before list_console_messages or get_console_message — neither returns anything until collection is on. Network capture, by contrast, is always on and needs no equivalent call. This is opt-in rather than automatic because it enables the CDP Runtime domain, which some anti-bot scripts probe for to detect an attached debugger. Leave it off while stealth matters, and use disable_console_collection when you are done debugging. Applies per page: a new tab needs its own call.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
NameTypeReqDescription
resultstringyes

No examples provided.

evaluate_script ~532

Run JavaScript inside the page and get the result back as JSON. The escape hatch for anything the other tools do not cover: reading computed styles, calling a page's own JS API, or extracting structured data in a single round trip instead of a dozen snapshot-and-click cycles. Without `args` the function runs at page level in the main world. With `args`, the given uids become real element references, which is how you operate on one specific element from a snapshot. Return values must be JSON-serialisable — DOM nodes, functions and circular structures are not, so map them to plain values inside the function. A script that throws comes back as a failed call carrying the JavaScript error, not as a result you have to inspect for the word "Error". Pass script_path to run a function kept in a .js file, and file_path to write the result to disk instead of into the conversation.

NameTypeReqDescription
argsElement uids from the most recent take_snapshot, resolved to live DOM nodes and passed as the function's arguments. The first uid is also bound as `this`. Omit for page-level scripts.
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
file_pathstringWrite the JSON result to this local path instead of returning it — for extractions too large to put in the conversation.
framestringRun inside one of the page's frames instead of the main document: an index or frame id from list_frames. Runs in an isolated world, which shares the frame's DOM but not its own JavaScript variables,…
functionstringA JavaScript function expression, e.g. "() => document.title" or "(el) => el.innerText". It is invoked immediately and its return value is JSON-serialised back to you. Async functions are awaited, so…
script_pathstringRead the function from this local .js file instead of the `function` parameter. Use it for anything long or quote-heavy, where escaping the script into a JSON string is where the mistakes happen.
NameTypeReqDescription
resultstringyes

No examples provided.

fill ~380

Set the value of an input, textarea, select or contenteditable element. Selects whatever is already in the field and types over it, character by character, so `input` events fire and React/Vue-style controlled components register the change. It deliberately does not blank the field first: that makes such components re-render, the focus follows the replaced node, and the keystrokes end up nowhere. For <select>, the option is chosen by value and a `change` event is dispatched. The value is read back afterwards. If it did not land you get an error, not a success you cannot trust — a field can be read-only, disabled, covered by an overlay, or rewrite what you type, and silently reporting success would send you looking for the problem several steps later. Use type_text instead when you want to append to a focused field rather than replace its contents. For several fields at once, fill_form does it in one round trip.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
include_snapshotbooleanAppend a fresh page snapshot to the response. Worth it when this action changes the page and take_snapshot would be your next call anyway — it saves a round trip, at the cost of a much larger respons…
uidstringyesElement uid from the most recent take_snapshot, e.g. "4_12". uids are invalidated whenever the page changes — if you get "unknown uid", take a fresh snapshot and retry with the new uid.
valuestringyesThe text to enter. For a <select> element this must match the option's value attribute, not its visible label.
NameTypeReqDescription
resultstringyes

No examples provided.

fill_form ~215

Fill several form fields in a single call. Behaves like `fill` per field, but costs one round trip instead of one per field. Fields are processed in the order given, which matters on pages that reveal or enable later fields in response to earlier ones. A field that fails does not abort the rest: the response reports success or the specific error per uid, so a partially filled form is always visible rather than silent.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
elementsarrayyesThe fields to fill, in order — each entry is {"uid": "...", "value": "..."}.
include_snapshotbooleanAppend a fresh page snapshot to the response. Worth it when this action changes the page and take_snapshot would be your next call anyway — it saves a round trip, at the cost of a much larger respons…
NameTypeReqDescription
resultstringyes

No examples provided.

get_computed_styles ~326

Read an element's computed styles, as the browser actually resolved them. Computed styles are the end result of the whole cascade, so this answers what a stylesheet alone cannot: why an element is invisible (`display: none`, `visibility: hidden`, `opacity: 0`), what a CSS variable resolved to, or which font actually got used. Also reports the element's box: position, size, and whether it is currently in the viewport. An element with zero width or height is present in the DOM but not rendered, which is the usual reason a click appears to do nothing. By default only properties that differ from the browser default are returned, because the full set runs to several hundred entries and buries the interesting ones.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
propertiesOnly return these CSS properties, e.g. ["display", "color", "font-size"]. Omit to get the properties that differ from the browser default, which is usually what you want — the full computed set is se…
selectorstringCSS selector of the element to inspect, e.g. "#header" or ".btn.primary". The first match is used. Leave empty to use `uid` instead.
uidstringElement uid from the most recent take_snapshot, as an alternative to `selector`. Ignored when `selector` is given.
NameTypeReqDescription
resultstringyes

No examples provided.

get_console_message ~138

Read one console message in full, by id. list_console_messages truncates every entry to 200 characters; use this to get a complete stack trace or error payload. Requires enable_console_collection to have been called for this page. The server leaves the CDP Runtime domain disabled by default because enabling it is itself something sites can detect.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
msgidintegeryesMessage id, as shown in square brackets by list_console_messages.
NameTypeReqDescription
resultstringyes

No examples provided.

get_cookies ~155

List browser cookies with their domain, path and secure flag. Reads the whole browser cookie jar, not just the current page, unless you pass `url`. Values are returned in full, so treat the output as sensitive — it contains live session tokens. To carry these across a browser restart use save_session, or switch to a persistent profile with use_profile.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
urlstringOnly return cookies that would be sent to this URL (matching domain, path and secure flag). Empty string returns every cookie in the browser.
NameTypeReqDescription
resultstringyes

No examples provided.

get_local_storage ~118

Read all localStorage entries for the current page's origin. Values are truncated to 200 characters each; for one entry in full use evaluate_script with `() => localStorage.getItem("key")`. localStorage is scoped per origin, so this returns nothing on about:blank — navigate to the site first. sessionStorage is not included.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
NameTypeReqDescription
resultstringyes

No examples provided.

get_network_request ~263

Inspect one network request: URL, method, resource type and both bodies. Often the fastest way to get structured data out of a site: find the page's own API call with list_network_requests, then read the JSON it already received here, instead of scraping the rendered DOM. Inline bodies are truncated at 5000 characters, so pass a file path for anything larger. Response bodies are only available while Chrome still holds them in its buffer — for a long-finished request the entry may still be listed while its body is already gone.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
reqidRequest id, as shown in square brackets by list_network_requests. Omit to get the most recent request.
request_file_pathstringWrite the request body (POST data) to this local file path instead of including it in the response.
response_file_pathstringWrite the response body to this local file path instead of including it. Use this for binary responses (images, PDFs, archives) — they are base64-decoded on the way out.
NameTypeReqDescription
resultstringyes

No examples provided.

get_page_content ~352

Get the page's visible text, or its full HTML. The cheapest way to read a page when you only need content and not the uids take_snapshot provides: no accessibility tree is built, and the text form carries no markup overhead. Returns the DOM as it stands right now, so on pages that render asynchronously call wait_for or wait_for_selector first. Use take_snapshot when you intend to interact with elements, and query_selector when you want specific elements rather than the whole page.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
file_pathstringWrite the content to this local path instead of returning it — the way to capture a large page without flooding the conversation.
formatstring"text" returns document.body.innerText — visible text without markup, which is what you want for reading. "html" returns the full outerHTML including scripts and attributes, needed when you care abou…
framestringRead inside one of the page's frames instead of the main document: an index or frame id from list_frames. Chrome's DOM queries never cross a frame boundary, so anything inside an iframe is unreachabl…
max_charsintegerTruncate the output at this many characters. 0 means no limit, which is risky on large pages — especially with format="html".
NameTypeReqDescription
resultstringyes

No examples provided.

handle_dialog ~195

Answer an open JavaScript dialog — alert, confirm or prompt. A dialog blocks the page and every subsequent tool call until it is handled, so call this as soon as one appears. Returns an error if no dialog is open. beforeunload dialogs triggered by navigating away are handled automatically via navigate_page's `handle_before_unload` parameter; this tool is for dialogs the page opens by itself.

NameTypeReqDescription
actionstringAccept (OK) or dismiss (Cancel) the dialog. Either closes an alert(); for confirm() the choice is what the page's JavaScript receives.
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
prompt_textstringText to enter into a prompt() dialog before accepting it. Ignored for alert() and confirm() dialogs.
NameTypeReqDescription
resultstringyes

No examples provided.

hover ~255

Move the mouse over an element without clicking it. This is how you open hover-triggered menus, tooltips and dropdowns before reading what they reveal — pass include_snapshot=true to get the revealed content back in the same call. The element is scrolled into view and hit-tested first, the same way click does it: a point that lands on a sticky header instead opens that header's menu, not the one you asked for. If something covers the element, this says what, rather than hovering the wrong thing.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
include_snapshotbooleanAppend a fresh page snapshot to the response. Worth it when this action changes the page and take_snapshot would be your next call anyway — it saves a round trip, at the cost of a much larger respons…
uidstringyesElement uid from the most recent take_snapshot, e.g. "4_12". uids are invalidated whenever the page changes — if you get "unknown uid", take a fresh snapshot and retry with the new uid.
NameTypeReqDescription
resultstringyes

No examples provided.

list_browsers ~142

List every browser this server currently holds: its name, whether its Chrome is running, which profile it uses, how many tabs it has and what they show. Reports without starting anything. There is always a browser called "default", which runs in the server process. Others are created implicitly, by passing a new name as the `browser` argument of any tool, so this only shows names already used. A name missing here is not an error; it simply has not been opened. chrome_running=false means the browser exists but has no Chrome, either because no tool has needed one yet or because close_browser was called. The next call relaunches it.

Input schema present but exposes no named parameters.

No output schema declared.

No examples provided.

list_console_messages ~248

List console output collected for the selected page. Requires enable_console_collection first. Console capture is opt-in because it needs the CDP Runtime domain, which some sites use to detect an attached debugger; without it this returns a reminder instead of messages. Each line is prefixed with its id and truncated to 200 characters — pass the id to get_console_message for the full text. Only the most recent 1000 messages are retained.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
include_preserved_messagesbooleanAlso include messages from before the last navigation — the server keeps the previous 3 navigations. Default false: current page only.
page_idxinteger0-based page number, used together with page_size.
page_sizeMaximum number of messages to return. Omit to return all.
typesOnly return these console types, e.g. ["error", "warning"]. Note the value is "warning", not "warn". Omit for all types.
NameTypeReqDescription
resultstringyes

No examples provided.

list_frames ~155

List the page's frames, so their content can be reached at all. Chrome's accessibility tree stops at a frame boundary, and document.querySelector never crosses one, so anything inside an iframe — payment fields, consent walls, embedded editors, CAPTCHA widgets — is invisible to take_snapshot and query_selector by default. Index 0 is always the main frame. Pass an index or frame id as the `frame` argument of get_page_content, query_selector, evaluate_script, wait_for_selector or take_snapshot to work inside one.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
NameTypeReqDescription
resultstringyes

No examples provided.

list_network_requests ~301

List the network requests the selected page has made. Collection is automatic — unlike console capture, nothing needs enabling. The main use is finding the JSON API a page calls: filter with resource_types=["XHR", "Fetch"], then pass the id from the square brackets to get_network_request to read the actual response body. That is usually far cheaper and more reliable than scraping the rendered DOM. Only the most recent 1000 requests are retained, and each URL is truncated to 150 characters in this listing.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
include_preserved_requestsbooleanAlso include requests from before the last navigation — the server keeps the previous 3 navigations. Default false: current page only.
page_idxinteger0-based page number, used together with page_size.
page_sizeMaximum number of requests to return. Omit to return all.
resource_typesOnly return these resource types. ["XHR", "Fetch"] is the useful filter for finding a page's own API calls. Matching is case-insensitive. Omit for all types.
url_filterstringOnly return requests whose URL contains this substring (plain text, not a regex), e.g. "/api/" or "graphql".
NameTypeReqDescription
resultstringyes

No examples provided.

list_pages ~184

List every open browser tab with its index, URL and title. The index shown here is the `page_id` taken by select_page and close_page. Indices are positional and shift whenever a tab opens or closes, so re-read them here rather than reusing an index from an earlier call. Tools act on the page chosen with select_page, or on the most recently opened tab if none was selected; the selected one is marked here. Each entry also carries the page's CDP targetId, which is the stable identity of a tab: unlike the index it survives other tabs opening and closing, and it is what CDP-level tooling and logs refer to.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
NameTypeReqDescription
resultstringyes

No examples provided.

list_profiles ~148

List persistent Chrome profiles and show which one is active. By default the browser runs on a fresh ephemeral temp profile that is deleted when the session ends. That default is what lets several nodriver instances — Claude Desktop, Claude Code, the VS Code extension — run at the same time without fighting over one profile directory. Persistent profiles keep cookies, logins and installed extensions across sessions. Create one with create_profile, switch with use_profile, and return to ephemeral with use_temp_profile.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
NameTypeReqDescription
resultstringyes

No examples provided.

list_sessions ~115

List saved session files with their name, save time and contents. Shows the filename to hand to load_session, along with how many cookies and localStorage entries each one holds, newest first. Sessions live in ~/.nodriver-mcp/sessions/ and are never cleaned up automatically, so old logins accumulate there over time.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
NameTypeReqDescription
resultstringyes

No examples provided.

load_session ~200

Restore cookies and localStorage from a saved session file. Use it at the start of a run to arrive already logged in. The page is first navigated to the saved origin so localStorage lands where it belongs, then reloaded so the restored cookies take effect. Cookies that no longer apply are skipped rather than failing the whole restore, and the response reports how many were actually restored. Expired tokens still leave you logged out, so check the page afterwards.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
filenamestringyesSession filename as shown by list_sessions, or an absolute path to a session JSON file.
restore_pagesbooleanAlso re-open the tabs that were open when the session was saved. Default false, which restores only cookies and localStorage.
NameTypeReqDescription
resultstringyes

No examples provided.

manage_extensions ~350

List, enable, disable or load Chrome extensions. Two separate mechanisms are in play. The master switch: Chrome runs with --disable-extensions by default, so extensions installed in the profile stay dark until it is turned on. And unpacked extensions loaded from a folder on disk. The master switch governs both — with it off, unpacked extensions stay registered but do not load. "load" only works on Chromium or Chrome for Testing. Official Google Chrome builds have ignored --load-extension since v137 (still true on Chrome 151, even with --enable-unsafe-extension-debugging), and this tool says so rather than pretending it worked. On official Chrome the working path is: install the extension once from the Web Store into a persistent profile, then switch it on with "on". Extensions only persist in a persistent profile — on the default ephemeral one nothing can stay installed.

NameTypeReqDescription
actionstring"list" shows the extensions installed in the active profile plus the current state, and changes nothing. "on" and "off" flip the master switch. "load" registers an unpacked extension from `path` and…
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
pathstringFolder containing the extension's manifest.json, for "load" and "unload". Ignored by the other actions.
NameTypeReqDescription
resultstringyes

No examples provided.

navigate_page ~484

Navigate the selected page — load a URL, or go back, forward or reload. Navigating rotates the collected logs: the previous page's console and network entries move into the preserved history (the last 3 navigations are kept), still reachable via `include_preserved_*` on the list tools. Passing `device` applies the emulation before the request is sent, so the server sees mobile signals on the very first byte — calling emulate_device afterwards is too late for that first request. Returns the resulting URL together with all open pages. This reuses the current tab; use new_page to open an additional one.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
devicestringDevice to emulate — sets user agent, UA client hints, viewport, device pixel ratio and touch together. Presets: "pixel_7" (aliases: pixel7, android, android_phone), "pixel_7_landscape" (pixel7_landsc…
handle_before_unloadstringHow to answer a beforeunload confirmation ("Leave site?") raised by the page being left. "accept" leaves, "dismiss" stays — in which case the navigation does not happen.
ignore_cachebooleanBypass the HTTP cache (a hard reload). Only applies to type="reload".
init_scriptstringJavaScript executed in every new document before any of the page's own scripts, for this navigation. Use it to stub out APIs or plant values a page reads at startup. Plain statements, not a function…
timeoutintegerMaximum wait in milliseconds. 0 uses the built-in default.
typestringThe kind of navigation: "url" loads `url`, "back" and "forward" move through session history, "reload" reloads the current page.
urlstringTarget URL — required when type="url", ignored otherwise. Include the scheme: "https://example.com", not "example.com".
NameTypeReqDescription
resultstringyes

No examples provided.

new_page ~423

Open a new browser tab and load a URL. Chrome always starts with one tab, so the first call here reuses that empty startup tab rather than leaving a stray blank page behind for the rest of the session. A blank tab sitting among others is left alone, and an isolated context always gets a target of its own. Unless `background` is set, the new page becomes the selected page for every subsequent tool call. Passing `device` applies emulation before the first real request, so mobile signals are present from the very first byte — which calling emulate_device afterwards cannot achieve.

NameTypeReqDescription
backgroundbooleanOpen the tab without focusing it, leaving the current page selected. Default false, which focuses the new page and makes it the target of all following tool calls.
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
devicestringDevice to emulate — sets user agent, UA client hints, viewport, device pixel ratio and touch together. Presets: "pixel_7" (aliases: pixel7, android, android_phone), "pixel_7_landscape" (pixel7_landsc…
isolated_contextstringOpen the page in a named isolated browser context — its own cookie jar and storage, comparable to a separate incognito window. Pages given the same name share that context; different names are fully…
timeoutintegerMaximum wait in milliseconds. 0 uses the built-in default.
urlstringURL to load in the new tab, including the scheme. Defaults to "about:blank" for an empty tab.
NameTypeReqDescription
resultstringyes

No examples provided.

performance_start_trace ~287

Record a Chrome performance trace of page load or interaction. Captures the same DevTools timeline categories the Performance panel uses: rendering, scripting, loading, screenshots and the V8 CPU profile. With the defaults (reload + auto_stop) this is one self-contained call that reloads, records for ~5s and returns. Only one trace can run at a time. Pass file_path to keep the data — without it you get just an event count, which confirms the trace ran but says nothing about what it measured. The output is raw trace JSON: load it via DevTools -> Performance -> Load profile.

NameTypeReqDescription
auto_stopbooleanRecord for about 5 seconds, then stop and return the result in this same call. Default true. Set false to control the window yourself and end it with performance_stop_trace.
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
file_pathstringWrite the raw trace JSON to this local path. Omit to get only the collected event count back.
reloadbooleanReload the page after starting the trace so the recording covers page load. Default true, which is what you want for load performance; set false to profile the page as it currently stands.
NameTypeReqDescription
resultstringyes

No examples provided.

performance_stop_trace ~139

Stop the running performance trace and collect its data. Only needed when performance_start_trace was called with auto_stop=false — otherwise the trace has already ended and this returns an error. Waits up to 30 seconds for Chrome to flush its buffered events.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
file_pathstringWrite the raw trace JSON to this local path (e.g. "trace.json"), loadable in DevTools -> Performance. Omit to get only the event count.
NameTypeReqDescription
resultstringyes

No examples provided.

press_key ~307

Send a key press or keyboard shortcut to the page. Goes to whatever currently holds focus, so click or fill the target element first — with nothing focused the key lands on the document body. Modifiers are held around the main key with the proper modifier bitmask, so real chords such as Control+A or Control+Shift+R register as shortcuts instead of arriving as unrelated key presses. For entering text use fill (replaces the field) or type_text (appends to it); this tool is for single keys and shortcuts.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
include_snapshotbooleanAppend a fresh page snapshot to the response. Worth it when this action changes the page and take_snapshot would be your next call anyway — it saves a round trip, at the cost of a much larger respons…
keystringyesA key or chord, e.g. "Enter", "Tab", "Escape", "ArrowDown", "a", "Control+A" or "Control+Shift+R". Modifiers are Control, Shift, Alt and Meta, joined with +. Named keys: Enter, Tab, Backspace, Delete…
NameTypeReqDescription
resultstringyes

No examples provided.

query_selector ~276

Find elements by CSS selector; list their tag, text, href, id and class. The efficient way to pull a repeated structure off a page — search results, product tiles, table rows — without paying for a full snapshot. Returns a compact listing only. It yields no uids, so it cannot drive clicks: take a snapshot when you need to interact, or operate on the elements directly via evaluate_script. Element text is truncated to 200 characters.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
framestringRead inside one of the page's frames instead of the main document: an index or frame id from list_frames. Chrome's DOM queries never cross a frame boundary, so anything inside an iframe is unreachabl…
limitintegerMaximum number of matching elements to return.
selectorstringyesA CSS selector, e.g. "a.result", "#nav li", "input[type=file]". Standard querySelectorAll syntax — no jQuery extensions such as :contains().
NameTypeReqDescription
resultstringyes

No examples provided.

reset_emulation ~138

Clear every emulation override on the selected page. Resets in one call: network throttling, CPU throttling, geolocation, user agent and client hints, color scheme, viewport, device pixel ratio, page scale and touch emulation — back to the real browser defaults. Use after emulate or emulate_device to make the page behave like ordinary desktop Chrome again. Turning touch emulation off here also restores trusted CDP clicks.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
NameTypeReqDescription
resultstringyes

No examples provided.

resize_page ~163

Resize the browser window so the page gets the given dimensions. Moves the actual OS window, which is what you want for responsive-layout checks that should also come out right in a screenshot. To emulate a viewport size without touching the window — including device pixel ratio, the mobile flag and touch — use emulate's `viewport` parameter or emulate_device. Those are what a site's media queries and fingerprinting read as a genuine device change.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
heightintegeryesTarget page height in CSS pixels.
widthintegeryesTarget page width in CSS pixels.
NameTypeReqDescription
resultstringyes

No examples provided.

save_pdf ~190

Export the current page to a PDF using Chrome's print-to-PDF. Renders the entire document rather than just the viewport, and applies the page's print stylesheet — so the result can differ from the screen layout. A good way to archive a rendered page as one file. For a pixel-accurate copy of what is on screen, use take_screenshot with full_page instead.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
file_pathstringyesLocal path to write the .pdf file to.
landscapebooleanUse landscape orientation instead of portrait.
print_backgroundbooleanInclude background colours and images. Default true, which resembles the page as seen on screen; false gives the leaner print view.
NameTypeReqDescription
resultstringyes

No examples provided.

save_session ~199

Save cookies, localStorage and open page URLs to a reusable file. This is how you keep a login obtained interactively, so a later run can skip the login flow entirely — restore it with load_session. Stored as JSON under ~/.nodriver-mcp/sessions/. That file holds live session tokens in plain text, so treat it as a credential. Only the current page's origin contributes localStorage. For a login meant to survive without an explicit restore step, a persistent profile (create_profile + use_profile) is the sturdier option.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
namestringyesA human-readable name for this session, e.g. "github-logged-in". It forms the filename, with a timestamp appended so repeated saves never overwrite one another.
NameTypeReqDescription
resultstringyes

No examples provided.

scroll_page ~215

Scroll the page up or down by a percentage of the viewport. The way to trigger lazy-loaded content and infinite scroll; take a fresh take_snapshot afterwards to see what was added. The response reports how far the page actually moved and whether the end has been reached, so a scroll loop has something to stop on: "did not move" means you are at the end, and a page height that keeps growing means more content is still loading. To bring one known element into view, scroll_to_selector is more precise. `click` already scrolls to its target, so no scrolling is needed before it.

NameTypeReqDescription
amountintegerHow far to scroll, as a percentage of the viewport height — 25 is a quarter screen, 100 a full screen.
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
directionstringDirection to scroll.
NameTypeReqDescription
resultstringyes

No examples provided.

scroll_to_selector ~141

Scroll the first element matching a CSS selector into view, centered. More precise than scroll_page when you already know what you are looking for, and the usual preparation for click_at, which needs its target inside the viewport. `click` scrolls to its own target, so this is unnecessary before it. Reports whether anything matched instead of failing silently.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
selectorstringyesCSS selector of the element to scroll to; the first match wins.
NameTypeReqDescription
resultstringyes

No examples provided.

select_option ~271

Choose an option in a <select>, by value, visible label or index. fill also works on a <select>, but only matches the value attribute, which is not what a snapshot shows you — so it had to be guessed. This matches what you can actually see, and when nothing matches it lists the real options instead of only saying no.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
include_snapshotbooleanAppend a fresh page snapshot to the response. Worth it when this action changes the page and take_snapshot would be your next call anyway — it saves a round trip, at the cost of a much larger respons…
optionstringyesThe option to choose. Matched against the value attribute first, then the visible label, then — if it is a plain number — the position in the list. A failure names every option the <select> actually…
uidstringyesElement uid from the most recent take_snapshot, e.g. "4_12". uids are invalidated whenever the page changes — if you get "unknown uid", take a fresh snapshot and retry with the new uid.
NameTypeReqDescription
resultstringyes

No examples provided.

select_page ~210

Choose which open tab every subsequent tool call acts on. Without a selection, tools act on the most recently opened tab. Selecting makes that choice explicit and sticky — needed when a click opened a tab you now want to drive, or when working across several sites at once. Indices come from list_pages and shift as tabs open and close, so the response lists them again. If the selected tab is later closed, the selection is dropped and the default applies again.

NameTypeReqDescription
bring_to_frontbooleanAlso focus the tab in the real browser window. Default true. Many pages pause animations, timers and media while backgrounded, so leave this on unless you specifically want the page to stay hidden.
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
page_idintegeryesIndex of the page to select, as listed by list_pages.
NameTypeReqDescription
resultstringyes

No examples provided.

set_browser_flags ~312

Change Chrome's launch flags at runtime, and show the current ones. Call with no arguments at all to just read the effective configuration — that form changes nothing. These are launch-time flags, so applying them restarts Chrome and closes every open page; on an ephemeral profile that also drops its cookies. Values set here override the NODRIVER_ENABLE_* environment variables.

NameTypeReqDescription
browserstringWhich browser to act on. Each name is an independent Chrome, created on first use. Omit for the shared default; parallel agents each need their own name.
extensionsTrue allows externally-installed Chrome extensions, false blocks them. Omit to leave unchanged. Blocked by default, so no "an extension requires your attention" prompt appears. manage_extensions offe…
extra_argsReplace the set of extra Chrome launch flags with this list, e.g. ["--lang=de-DE", "--window-size=1280,800"]. A leading "--" is added if missing. Pass [] to clear them, omit to leave unchanged. This…
restartbooleanRestart Chrome now so the flags take effect, closing all open pages. Default true; false defers them to the next browser start.
translateTrue allows Chrome's Google Translate popup, false suppresses it. Omit to leave unchanged. Suppressed by default, because the popup covers page content and swallows clicks.
NameTypeReqDescription
resultstringyes

No examples provided.

Common questions

What is the nodriver — undetected browser automation MCP server?

nodriver — undetected browser automation is an MCP server listed in the public MCP registry as io.github.andresolbach/nodriver-mcp-server. Undetected anti-bot Chrome automation. 65 tools, parallel isolated browsers. This page covers its PyPI package (nodriver-mcp).

Is the nodriver — undetected browser automation MCP server safe to use?

nodriver — undetected browser automation scores 65 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 21 September 2026. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

What tools does the nodriver — undetected browser automation MCP server expose?

nodriver — undetected browser automation exposes 65 tools: list_frames, bypass_insecure_warning, cf_verify, click, click_at, and 60 more. Their descriptions and schemas cost roughly 16,297 tokens of context every time the server is loaded.

Is the nodriver — undetected browser automation MCP server still maintained?

nodriver — undetected browser automation is still listed as active in the MCP registry. We last reached this channel on 21 September 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.