nodriver-mcp 1.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nodriver_mcp-1.7.0/LICENSE +22 -0
- nodriver_mcp-1.7.0/PKG-INFO +281 -0
- nodriver_mcp-1.7.0/README.md +258 -0
- nodriver_mcp-1.7.0/pyproject.toml +53 -0
- nodriver_mcp-1.7.0/setup.cfg +4 -0
- nodriver_mcp-1.7.0/src/nodriver_mcp/__init__.py +1 -0
- nodriver_mcp-1.7.0/src/nodriver_mcp/__main__.py +6 -0
- nodriver_mcp-1.7.0/src/nodriver_mcp/cli.py +109 -0
- nodriver_mcp-1.7.0/src/nodriver_mcp/installer.py +285 -0
- nodriver_mcp-1.7.0/src/nodriver_mcp/installer_data.py +166 -0
- nodriver_mcp-1.7.0/src/nodriver_mcp/installer_tui.py +150 -0
- nodriver_mcp-1.7.0/src/nodriver_mcp/server.py +4260 -0
- nodriver_mcp-1.7.0/src/nodriver_mcp.egg-info/PKG-INFO +281 -0
- nodriver_mcp-1.7.0/src/nodriver_mcp.egg-info/SOURCES.txt +18 -0
- nodriver_mcp-1.7.0/src/nodriver_mcp.egg-info/dependency_links.txt +1 -0
- nodriver_mcp-1.7.0/src/nodriver_mcp.egg-info/entry_points.txt +2 -0
- nodriver_mcp-1.7.0/src/nodriver_mcp.egg-info/requires.txt +4 -0
- nodriver_mcp-1.7.0/src/nodriver_mcp.egg-info/top_level.txt +1 -0
- nodriver_mcp-1.7.0/tests/test_docs_consistency.py +75 -0
- nodriver_mcp-1.7.0/tests/test_tool_schemas.py +198 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Saber-CC (original nodriver-mcp)
|
|
4
|
+
Copyright (c) 2026 Andre Solbach (nodriver-mcp-server fork)
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nodriver-mcp
|
|
3
|
+
Version: 1.7.0
|
|
4
|
+
Summary: Undetected Chrome automation MCP server powered by nodriver — a stealth, anti-bot-resistant alternative to chrome-devtools-mcp for Claude, Cursor and other AI agents
|
|
5
|
+
Author: Andre Solbach
|
|
6
|
+
Maintainer: Andre Solbach
|
|
7
|
+
Project-URL: Homepage, https://github.com/andresolbach/nodriver-mcp-server
|
|
8
|
+
Project-URL: Repository, https://github.com/andresolbach/nodriver-mcp-server
|
|
9
|
+
Project-URL: Issues, https://github.com/andresolbach/nodriver-mcp-server/issues
|
|
10
|
+
Keywords: mcp,model-context-protocol,mcp-server,nodriver,chrome,browser-automation,web-scraping,undetected,anti-bot,cloudflare-bypass,claude,cursor,ai-agent,llm,chrome-devtools-mcp,playwright-alternative,puppeteer-alternative
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Requires-Python: >=3.12
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: mcp<2,>=1.26.0
|
|
19
|
+
Requires-Dist: nodriver>=0.50.3
|
|
20
|
+
Requires-Dist: pillow>=12.1.1
|
|
21
|
+
Requires-Dist: tomli-w>=1.0.0
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
|
|
24
|
+
<p align="center">
|
|
25
|
+
<img src="assets/logo.svg" alt="nodriver-mcp-server — undetected browser automation MCP server" width="130" height="130">
|
|
26
|
+
</p>
|
|
27
|
+
|
|
28
|
+
# nodriver-mcp-server
|
|
29
|
+
|
|
30
|
+
**An undetected, anti-bot-resistant browser automation MCP server** — a drop-in, stealth alternative to [`chrome-devtools-mcp`](https://github.com/ChromeDevTools/chrome-devtools-mcp) for AI agents like **Claude**, **Claude Code**, **Cursor**, **Windsurf**, and any [Model Context Protocol](https://modelcontextprotocol.io) client. Powered by [nodriver](https://github.com/ultrafunkamsterdam/nodriver) so your agent can browse, scrape, and automate real Chrome **without tripping Cloudflare, hCaptcha, or WebDriver fingerprint detection**.
|
|
31
|
+
|
|
32
|
+
[](https://pypi.org/project/nodriver-mcp/)
|
|
33
|
+
[](https://github.com/andresolbach/nodriver-mcp-server/actions/workflows/ci.yml)
|
|
34
|
+

|
|
35
|
+

|
|
36
|
+

|
|
37
|
+

|
|
38
|
+

|
|
39
|
+
|
|
40
|
+
> **Keywords:** MCP server · browser automation · undetected chromedriver · anti-bot · Cloudflare bypass · web scraping · Claude · Cursor · nodriver · chrome-devtools-mcp alternative · Playwright/Puppeteer alternative · AI agent tools.
|
|
41
|
+
|
|
42
|
+
## Why?
|
|
43
|
+
|
|
44
|
+
`chrome-devtools-mcp` and most Playwright/Puppeteer-based servers drive Chrome through CDP/WebDriver in a way that leaves detectable fingerprints (`navigator.webdriver`, CDP artifacts). Anti-bot systems (Cloudflare, hCaptcha, DataDome, etc.) flag these instantly.
|
|
45
|
+
|
|
46
|
+
`nodriver` is the successor of `undetected-chromedriver`. It talks **directly to the CDP protocol** — no ChromeDriver binary, no Selenium/WebDriver markers — so automated sessions look like a real user. This server exposes that power through the **same tool surface as `chrome-devtools-mcp`** (57 tools), so your agent gets a familiar API with far better stealth.
|
|
47
|
+
|
|
48
|
+
## Features
|
|
49
|
+
|
|
50
|
+
- 🕵️ **Undetected by design** — `navigator.webdriver` is `undefined`, no CDP fingerprints.
|
|
51
|
+
- ☁️ **Built-in Cloudflare challenge solver** (`cf_verify`).
|
|
52
|
+
- 🧩 **57 tools** covering navigation, input, snapshots, screenshots, content/PDF export, network + console inspection, device emulation, cookies/storage, sessions, profiles, and performance tracing.
|
|
53
|
+
- 🧠 **Schemas written for the agent, not just the compiler** — every parameter carries a description, fixed-value options are real enums, and each tool declares read-only/destructive hints. See [why this matters](#built-for-the-agent-that-calls-it).
|
|
54
|
+
- 📄 **Accessibility-tree snapshots** (`take_snapshot`) — searchable, LLM-friendly page text that's far smaller and faster than screenshots.
|
|
55
|
+
- 📱 **Device emulation** (Pixel 7, iPad) with correct UA / client hints.
|
|
56
|
+
- 💾 **Session save/restore** — persist logins across runs.
|
|
57
|
+
- 🧬 **Ephemeral by default, run many at once** — each session gets its own temp Chrome profile (auto-deleted), so Claude Desktop, Claude Code and VS Code can all drive nodriver **simultaneously without colliding**. Named **persistent profiles** are available on demand for reusable logins.
|
|
58
|
+
- ⚡ **One-command setup** for 15+ MCP clients.
|
|
59
|
+
|
|
60
|
+
## Installation
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# Recommended: isolated install, won't touch your global Python environment
|
|
64
|
+
uv tool install nodriver-mcp
|
|
65
|
+
|
|
66
|
+
# or with pip
|
|
67
|
+
pip install nodriver-mcp
|
|
68
|
+
|
|
69
|
+
# or run it without installing anything
|
|
70
|
+
uvx nodriver-mcp
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Requires [uv](https://docs.astral.sh/uv/getting-started/installation/) for the first and third form. To track the development branch instead of a release:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
uv tool install "nodriver-mcp @ git+https://github.com/andresolbach/nodriver-mcp-server.git@main"
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
> Uses upstream [`nodriver`](https://pypi.org/project/nodriver/) `>=0.50.3`, which contains the Chrome 146+ CDP fixes (`sameParty` removed from `Cookie`, `privateNetworkRequestPolicy` → `localNetworkAccessRequestPolicy`) — **verified working against Chrome 150**. `pip install` also works, but `uv tool install` keeps it isolated.
|
|
80
|
+
|
|
81
|
+
You'll also need a local installation of **Google Chrome** (auto-detected).
|
|
82
|
+
|
|
83
|
+
### Upgrade
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
uv tool upgrade nodriver-mcp
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Requirements & tested versions
|
|
90
|
+
|
|
91
|
+
Every tool in this server was tested **end-to-end against Google Chrome 150** with **nodriver 0.50.3** on **Python 3.12.11 / Windows 11** (macOS and Linux are supported too). Because nodriver talks to Chrome directly over CDP and tracks upstream Chrome changes, it keeps working as Chrome auto-updates.
|
|
92
|
+
|
|
93
|
+
| Component | Requirement | Verified version |
|
|
94
|
+
|-----------|-------------|------------------|
|
|
95
|
+
| Python | 3.12+ | 3.12.11 |
|
|
96
|
+
| Google Chrome | any recent stable | 150.0.7871.101 |
|
|
97
|
+
| Operating system | Windows / macOS / Linux | Windows 11 |
|
|
98
|
+
| `nodriver` | >= 0.50.3 | 0.50.3 |
|
|
99
|
+
| `mcp` (MCP SDK) | >= 1.26.0, < 2 | 1.26.0 |
|
|
100
|
+
| `pillow` | >= 12.1.1 | 12.1.1 |
|
|
101
|
+
| `tomli-w` | >= 1.0.0 | 1.2.0 |
|
|
102
|
+
|
|
103
|
+
The pip packages/versions are also listed in [`requirements.txt`](requirements.txt) (`pip install -r requirements.txt`), though `uv tool install` is recommended for a fully pinned, reproducible install.
|
|
104
|
+
|
|
105
|
+
## One-command MCP client setup
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
# Interactive client selector (terminal TUI)
|
|
109
|
+
nodriver-mcp install
|
|
110
|
+
|
|
111
|
+
# Install to specific clients
|
|
112
|
+
nodriver-mcp install claude,cursor,kiro
|
|
113
|
+
|
|
114
|
+
# Uninstall
|
|
115
|
+
nodriver-mcp uninstall claude
|
|
116
|
+
|
|
117
|
+
# List all supported clients
|
|
118
|
+
nodriver-mcp --list-clients
|
|
119
|
+
|
|
120
|
+
# Print MCP config JSON (for manual setup)
|
|
121
|
+
nodriver-mcp --config
|
|
122
|
+
|
|
123
|
+
# Project-level config (writes to .cursor/mcp.json, .mcp.json, etc.)
|
|
124
|
+
nodriver-mcp install --scope project
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Supported clients:** Claude Desktop, Claude Code, Cursor, Windsurf, Codex, Gemini CLI, Copilot CLI, Kiro, VS Code, Cline, Roo Code, Amazon Q, Warp, Opencode, Trae.
|
|
128
|
+
|
|
129
|
+
> The Claude Code VS Code extension shares Claude Code's config (`~/.claude.json`), so installing to `claude-code` covers both the CLI and the extension.
|
|
130
|
+
|
|
131
|
+
### Manual config
|
|
132
|
+
|
|
133
|
+
If you'd rather paste it yourself, this works in any MCP client (`claude_desktop_config.json`, `~/.claude.json`, `.cursor/mcp.json`, `.mcp.json`, …):
|
|
134
|
+
|
|
135
|
+
```json
|
|
136
|
+
{
|
|
137
|
+
"mcpServers": {
|
|
138
|
+
"nodriver": {
|
|
139
|
+
"command": "uvx",
|
|
140
|
+
"args": ["nodriver-mcp"]
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Environment Variables
|
|
147
|
+
|
|
148
|
+
| Variable | Description | Default |
|
|
149
|
+
|----------|-------------|---------|
|
|
150
|
+
| `NODRIVER_HEADLESS` | Headless mode (`true`/`false`) | `false` |
|
|
151
|
+
| `NODRIVER_USER_DATA_DIR` | Explicit persistent Chrome profile dir (overrides the default) | Ephemeral temp profile, auto-deleted per session |
|
|
152
|
+
| `NODRIVER_BROWSER_PATH` | Chrome executable path | Auto-detected |
|
|
153
|
+
| `NODRIVER_PROXY` | Proxy server address | None |
|
|
154
|
+
| `NODRIVER_ENABLE_TRANSLATE` | Set `true` to re-enable Chrome's Google Translate popup | Disabled |
|
|
155
|
+
| `NODRIVER_ENABLE_EXTENSIONS` | Set `true` to allow externally-installed Chrome extensions (and their prompts) | Disabled |
|
|
156
|
+
|
|
157
|
+
By default the browser starts clean for automation: the **Google Translate popup is suppressed** and **externally-installed Chrome extensions are blocked** (so you don't get "an extension requires your attention" prompts). Re-enable either via the env vars above **or at runtime with the `set_browser_flags` tool** — which can also set **any other Chrome launch flags** (e.g. `--lang=de-DE`, `--window-size=1280,800`) via its `extra_args` parameter. The browser also **auto-recovers** if Chrome is closed or crashes between calls — tools relaunch it instead of failing.
|
|
158
|
+
|
|
159
|
+
Chrome also starts on `about:blank` rather than the New Tab page, so the NTP's own Google requests never show up in `list_network_requests`, and `new_page` **reuses that empty startup tab** instead of leaving a stray blank page behind.
|
|
160
|
+
|
|
161
|
+
## Extensions
|
|
162
|
+
|
|
163
|
+
`manage_extensions` handles extensions at runtime:
|
|
164
|
+
|
|
165
|
+
- `manage_extensions("list")` — extensions installed in the active profile (name, version, id) plus the current state
|
|
166
|
+
- `manage_extensions("on")` / `("off")` — the master switch (`--disable-extensions`); restarts Chrome. It covers unpacked extensions too, so `"off"` really means off
|
|
167
|
+
- `manage_extensions("load", path)` / `("unload", path)` — unpacked extensions from a folder
|
|
168
|
+
|
|
169
|
+
To use an extension permanently, switch to a persistent profile, install it once from the Chrome Web Store in that browser, and turn extensions on — it then loads on every launch.
|
|
170
|
+
|
|
171
|
+
> **Unpacked extensions need Chromium or Chrome for Testing.** Official Chrome builds dropped `--load-extension` in v137, and as of Chrome 151 neither `--enable-unsafe-extension-debugging` nor disabling `DisableLoadExtensionCommandLineSwitch` brings it back — the flag is accepted and the extension is silently never registered. `manage_extensions` detects a branded build and says so instead of pretending it worked. Point `NODRIVER_BROWSER_PATH` at Chromium / Chrome for Testing if you need unpacked loading.
|
|
172
|
+
|
|
173
|
+
## Profiles & running multiple instances at once
|
|
174
|
+
|
|
175
|
+
By default every server instance launches Chrome with a **fresh temporary profile** that nodriver creates and deletes automatically. That means you can run nodriver from **Claude Desktop, Claude Code and the VS Code extension at the same time** — each gets its own isolated Chrome, and they never fight over a shared profile. No configuration, no detection logic, nothing to clean up.
|
|
176
|
+
|
|
177
|
+
When you want to **reuse a login across sessions**, create a named persistent profile and switch to it:
|
|
178
|
+
|
|
179
|
+
- `list_profiles` — list persistent profiles and show the active one
|
|
180
|
+
- `create_profile(name, activate=false)` — create a reusable profile
|
|
181
|
+
- `use_profile(name)` — switch to a persistent profile (`""`/`"temp"` returns to ephemeral)
|
|
182
|
+
- `use_temp_profile` — switch back to a fresh ephemeral profile
|
|
183
|
+
- `delete_profile(name)` — remove a persistent profile
|
|
184
|
+
|
|
185
|
+
Persistent profiles live under `~/.nodriver-mcp/profiles/<name>`. You can still force a fixed profile globally with the `NODRIVER_USER_DATA_DIR` env var.
|
|
186
|
+
|
|
187
|
+
## Tools (57)
|
|
188
|
+
|
|
189
|
+
Network collection is enabled automatically on each tab. Console collection is opt-in: call `enable_console_collection` when you want `list_console_messages` / `get_console_message` to start collecting events. This keeps `Runtime.enable()` disabled by default for sites that detect attached debuggers.
|
|
190
|
+
|
|
191
|
+
For mobile-only sites, pass `device` directly to `new_page(...)` or `navigate_page(...)` so the first real request already carries mobile signals.
|
|
192
|
+
|
|
193
|
+
`click` and `click_at` send **real CDP input events**, so the page sees `isTrusted=true`. A scripted click (`element.click()` plus synthetic events, `isTrusted=false`) is used only where real input cannot be delivered — on a touch-emulated target, or after the CDP click times out — and the response says when that happened, so a detectable click is never silent.
|
|
194
|
+
|
|
195
|
+
| Category | Tools |
|
|
196
|
+
|----------|-------|
|
|
197
|
+
| **Input automation (10)** | `click` · `click_at` · `hover` · `fill` · `fill_form` · `type_text` · `press_key` · `drag` · `upload_file` · `handle_dialog` |
|
|
198
|
+
| **Navigation (10)** | `navigate_page` · `new_page` · `close_page` · `close_browser` · `list_pages` · `select_page` · `wait_for` · `wait_for_selector` · `scroll_page` · `scroll_to_selector` |
|
|
199
|
+
| **Snapshots & debugging (10)** | `take_screenshot` · `take_snapshot` · `get_page_content` · `query_selector` · `evaluate_script` · `save_pdf` · `enable_console_collection` · `disable_console_collection` · `list_console_messages` · `get_console_message` |
|
|
200
|
+
| **Network monitoring (3)** | `list_network_requests` · `get_network_request` · `block_resources` |
|
|
201
|
+
| **Device emulation (4)** | `emulate` · `emulate_device` · `reset_emulation` · `resize_page` |
|
|
202
|
+
| **Performance (3)** | `performance_start_trace` · `performance_stop_trace` · `take_memory_snapshot` |
|
|
203
|
+
| **Cookies & storage (5)** | `get_cookies` · `set_cookie` · `clear_cookies` · `get_local_storage` · `set_local_storage` |
|
|
204
|
+
| **Session management (3)** | `save_session` · `load_session` · `list_sessions` |
|
|
205
|
+
| **Profiles & browser (7)** | `list_profiles` · `create_profile` · `use_profile` · `use_temp_profile` · `delete_profile` · `set_browser_flags` · `manage_extensions` |
|
|
206
|
+
| **Anti-detection helpers (2)** | `cf_verify` · `bypass_insecure_warning` |
|
|
207
|
+
|
|
208
|
+
📖 **[Full tool reference →](docs/TOOLS.md)** — every tool with its exact parameters, types, defaults and enum values, generated straight from the live schemas.
|
|
209
|
+
|
|
210
|
+
## Built for the agent that calls it
|
|
211
|
+
|
|
212
|
+
An MCP tool is only as good as what the model can see of it. Most servers hand over a name, a sentence, and untyped parameters — leaving the agent to guess whether it's `type="url"` or `type="goto"`, and burning a failed call to find out.
|
|
213
|
+
|
|
214
|
+
Here, the schema does that work:
|
|
215
|
+
|
|
216
|
+
- **Every parameter has a description in the schema itself** — not buried in a prose blob the client may never show. All 57 tools, all parameters, no exceptions (there's a test for it).
|
|
217
|
+
- **Fixed-value parameters are real enums.** `navigate_page(type=…)` advertises exactly `url`, `back`, `forward`, `reload`. A wrong value is rejected by validation before it ever reaches Chrome, instead of returning an error the agent has to interpret.
|
|
218
|
+
- **Numeric and array bounds are declared** — `quality` is 0–100, `wait_for(text=…)` requires at least one entry.
|
|
219
|
+
- **Structured parameters are typed.** `fill_form` publishes `{uid, value}` rather than an opaque `list[dict]`.
|
|
220
|
+
- **Every tool declares behaviour hints** (`readOnlyHint`, `destructiveHint`, `idempotentHint`). Clients use these to group permissions — so a client can auto-approve `take_snapshot` while still prompting for `delete_profile`.
|
|
221
|
+
- **Descriptions say when *not* to use a tool**, and point at the better one. `take_screenshot` tells the model to prefer `take_snapshot`; `click_at` points back to `click`.
|
|
222
|
+
|
|
223
|
+
## Comparison with chrome-devtools-mcp
|
|
224
|
+
|
|
225
|
+
| Feature | chrome-devtools-mcp | nodriver-mcp-server |
|
|
226
|
+
|---------|---------------------|---------------------|
|
|
227
|
+
| Browser backend | Puppeteer (ChromeDriver) | nodriver (direct CDP) |
|
|
228
|
+
| WebDriver fingerprint | ❌ Exposed | ✅ None |
|
|
229
|
+
| `navigator.webdriver` | ❌ `true` | ✅ `undefined` |
|
|
230
|
+
| Cloudflare bypass | ❌ | ✅ Built-in `cf_verify` |
|
|
231
|
+
| Install method | npx | uvx / pip |
|
|
232
|
+
| Language | TypeScript / Node.js | Python |
|
|
233
|
+
| Tool coverage | 29 tools | 57 tools |
|
|
234
|
+
| Per-parameter schema docs | partial | ✅ all 57 tools |
|
|
235
|
+
| Tool behaviour hints | ❌ | ✅ read-only / destructive |
|
|
236
|
+
|
|
237
|
+
Tools not implemented: `performance_analyze_insight` (needs the DevTools frontend trace parser), `lighthouse_audit` (needs the Lighthouse Node API), `screencast_start/stop` (needs ffmpeg + Puppeteer), extension management (experimental).
|
|
238
|
+
|
|
239
|
+
## Use cases
|
|
240
|
+
|
|
241
|
+
- **Scrape sites behind Cloudflare / anti-bot** (DataDome, PerimeterX, hCaptcha challenges) without being fingerprinted or blocked.
|
|
242
|
+
- **Let an AI agent browse the real web** — Claude, Cursor, Windsurf and other LLM agents can log in, fill forms, click, read pages, and screenshot.
|
|
243
|
+
- **Automate authenticated workflows** and reuse the login across sessions with persistent profiles.
|
|
244
|
+
- **LLM-driven web research & data extraction** using compact accessibility-tree snapshots instead of brittle screenshots.
|
|
245
|
+
- **End-to-end / QA testing** with device emulation, network + console inspection, and performance traces.
|
|
246
|
+
- An **undetected alternative to Playwright, Puppeteer and Selenium** for agentic browsing.
|
|
247
|
+
|
|
248
|
+
## FAQ
|
|
249
|
+
|
|
250
|
+
**Is this an undetected alternative to chrome-devtools-mcp?**
|
|
251
|
+
Yes. It exposes the same tool surface but drives Chrome through nodriver (direct CDP), so `navigator.webdriver` is `undefined` and there are no WebDriver/CDP fingerprints for anti-bot systems to detect.
|
|
252
|
+
|
|
253
|
+
**Can it bypass Cloudflare?**
|
|
254
|
+
It ships a `cf_verify` tool that solves the Cloudflare "verify you are human" challenge, and its undetected profile avoids most bot checks. (No tool can guarantee bypassing every protection.)
|
|
255
|
+
|
|
256
|
+
**Which clients are supported?**
|
|
257
|
+
One command installs it into 15+ MCP clients: Claude Desktop, Claude Code, Cursor, Windsurf, Codex, Gemini CLI, Copilot CLI, Kiro, VS Code, Cline, Roo Code, Amazon Q, Warp, Opencode, Trae.
|
|
258
|
+
|
|
259
|
+
**Can I run it in several clients at the same time?**
|
|
260
|
+
Yes. Each instance uses its own ephemeral Chrome profile by default, so Claude Desktop, Claude Code and the VS Code extension can all use nodriver **simultaneously** without colliding.
|
|
261
|
+
|
|
262
|
+
**Headless or visible browser?**
|
|
263
|
+
A real Chrome window by default; set `NODRIVER_HEADLESS=true` for headless.
|
|
264
|
+
|
|
265
|
+
**How do I keep a login between sessions?**
|
|
266
|
+
Create a persistent profile with `create_profile` and switch to it with `use_profile`, or use `save_session` / `load_session`.
|
|
267
|
+
|
|
268
|
+
**Does it work on Windows / macOS / Linux?**
|
|
269
|
+
Yes, all three. Tested on Windows 11 with Chrome 150 and Python 3.12.
|
|
270
|
+
|
|
271
|
+
## Changelog
|
|
272
|
+
|
|
273
|
+
See [CHANGES.md](CHANGES.md). Highlights: ephemeral-by-default Chrome profiles so multiple instances run at once (+ named persistent profiles), migrated to upstream `nodriver 0.50.3` (Chrome 150 verified), and fixed several previously-broken tools — `fill`/`fill_form`, `evaluate_script` with element args, `select_page` tab switching, `press_key` modifier chords (Ctrl+A/C/V), network/console lookup indexing, and Windows installer crashes.
|
|
274
|
+
|
|
275
|
+
## Credits
|
|
276
|
+
|
|
277
|
+
Based on [`nodriver-mcp`](https://github.com/Saber-CC/nodriver-mcp) by **Saber-CC** (MIT). Browser backend by [`nodriver`](https://github.com/ultrafunkamsterdam/nodriver) (ultrafunkamsterdam). Tool surface mirrors [`chrome-devtools-mcp`](https://github.com/ChromeDevTools/chrome-devtools-mcp).
|
|
278
|
+
|
|
279
|
+
## License
|
|
280
|
+
|
|
281
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/logo.svg" alt="nodriver-mcp-server — undetected browser automation MCP server" width="130" height="130">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# nodriver-mcp-server
|
|
6
|
+
|
|
7
|
+
**An undetected, anti-bot-resistant browser automation MCP server** — a drop-in, stealth alternative to [`chrome-devtools-mcp`](https://github.com/ChromeDevTools/chrome-devtools-mcp) for AI agents like **Claude**, **Claude Code**, **Cursor**, **Windsurf**, and any [Model Context Protocol](https://modelcontextprotocol.io) client. Powered by [nodriver](https://github.com/ultrafunkamsterdam/nodriver) so your agent can browse, scrape, and automate real Chrome **without tripping Cloudflare, hCaptcha, or WebDriver fingerprint detection**.
|
|
8
|
+
|
|
9
|
+
[](https://pypi.org/project/nodriver-mcp/)
|
|
10
|
+
[](https://github.com/andresolbach/nodriver-mcp-server/actions/workflows/ci.yml)
|
|
11
|
+

|
|
12
|
+

|
|
13
|
+

|
|
14
|
+

|
|
15
|
+

|
|
16
|
+
|
|
17
|
+
> **Keywords:** MCP server · browser automation · undetected chromedriver · anti-bot · Cloudflare bypass · web scraping · Claude · Cursor · nodriver · chrome-devtools-mcp alternative · Playwright/Puppeteer alternative · AI agent tools.
|
|
18
|
+
|
|
19
|
+
## Why?
|
|
20
|
+
|
|
21
|
+
`chrome-devtools-mcp` and most Playwright/Puppeteer-based servers drive Chrome through CDP/WebDriver in a way that leaves detectable fingerprints (`navigator.webdriver`, CDP artifacts). Anti-bot systems (Cloudflare, hCaptcha, DataDome, etc.) flag these instantly.
|
|
22
|
+
|
|
23
|
+
`nodriver` is the successor of `undetected-chromedriver`. It talks **directly to the CDP protocol** — no ChromeDriver binary, no Selenium/WebDriver markers — so automated sessions look like a real user. This server exposes that power through the **same tool surface as `chrome-devtools-mcp`** (57 tools), so your agent gets a familiar API with far better stealth.
|
|
24
|
+
|
|
25
|
+
## Features
|
|
26
|
+
|
|
27
|
+
- 🕵️ **Undetected by design** — `navigator.webdriver` is `undefined`, no CDP fingerprints.
|
|
28
|
+
- ☁️ **Built-in Cloudflare challenge solver** (`cf_verify`).
|
|
29
|
+
- 🧩 **57 tools** covering navigation, input, snapshots, screenshots, content/PDF export, network + console inspection, device emulation, cookies/storage, sessions, profiles, and performance tracing.
|
|
30
|
+
- 🧠 **Schemas written for the agent, not just the compiler** — every parameter carries a description, fixed-value options are real enums, and each tool declares read-only/destructive hints. See [why this matters](#built-for-the-agent-that-calls-it).
|
|
31
|
+
- 📄 **Accessibility-tree snapshots** (`take_snapshot`) — searchable, LLM-friendly page text that's far smaller and faster than screenshots.
|
|
32
|
+
- 📱 **Device emulation** (Pixel 7, iPad) with correct UA / client hints.
|
|
33
|
+
- 💾 **Session save/restore** — persist logins across runs.
|
|
34
|
+
- 🧬 **Ephemeral by default, run many at once** — each session gets its own temp Chrome profile (auto-deleted), so Claude Desktop, Claude Code and VS Code can all drive nodriver **simultaneously without colliding**. Named **persistent profiles** are available on demand for reusable logins.
|
|
35
|
+
- ⚡ **One-command setup** for 15+ MCP clients.
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
# Recommended: isolated install, won't touch your global Python environment
|
|
41
|
+
uv tool install nodriver-mcp
|
|
42
|
+
|
|
43
|
+
# or with pip
|
|
44
|
+
pip install nodriver-mcp
|
|
45
|
+
|
|
46
|
+
# or run it without installing anything
|
|
47
|
+
uvx nodriver-mcp
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Requires [uv](https://docs.astral.sh/uv/getting-started/installation/) for the first and third form. To track the development branch instead of a release:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
uv tool install "nodriver-mcp @ git+https://github.com/andresolbach/nodriver-mcp-server.git@main"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
> Uses upstream [`nodriver`](https://pypi.org/project/nodriver/) `>=0.50.3`, which contains the Chrome 146+ CDP fixes (`sameParty` removed from `Cookie`, `privateNetworkRequestPolicy` → `localNetworkAccessRequestPolicy`) — **verified working against Chrome 150**. `pip install` also works, but `uv tool install` keeps it isolated.
|
|
57
|
+
|
|
58
|
+
You'll also need a local installation of **Google Chrome** (auto-detected).
|
|
59
|
+
|
|
60
|
+
### Upgrade
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
uv tool upgrade nodriver-mcp
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Requirements & tested versions
|
|
67
|
+
|
|
68
|
+
Every tool in this server was tested **end-to-end against Google Chrome 150** with **nodriver 0.50.3** on **Python 3.12.11 / Windows 11** (macOS and Linux are supported too). Because nodriver talks to Chrome directly over CDP and tracks upstream Chrome changes, it keeps working as Chrome auto-updates.
|
|
69
|
+
|
|
70
|
+
| Component | Requirement | Verified version |
|
|
71
|
+
|-----------|-------------|------------------|
|
|
72
|
+
| Python | 3.12+ | 3.12.11 |
|
|
73
|
+
| Google Chrome | any recent stable | 150.0.7871.101 |
|
|
74
|
+
| Operating system | Windows / macOS / Linux | Windows 11 |
|
|
75
|
+
| `nodriver` | >= 0.50.3 | 0.50.3 |
|
|
76
|
+
| `mcp` (MCP SDK) | >= 1.26.0, < 2 | 1.26.0 |
|
|
77
|
+
| `pillow` | >= 12.1.1 | 12.1.1 |
|
|
78
|
+
| `tomli-w` | >= 1.0.0 | 1.2.0 |
|
|
79
|
+
|
|
80
|
+
The pip packages/versions are also listed in [`requirements.txt`](requirements.txt) (`pip install -r requirements.txt`), though `uv tool install` is recommended for a fully pinned, reproducible install.
|
|
81
|
+
|
|
82
|
+
## One-command MCP client setup
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# Interactive client selector (terminal TUI)
|
|
86
|
+
nodriver-mcp install
|
|
87
|
+
|
|
88
|
+
# Install to specific clients
|
|
89
|
+
nodriver-mcp install claude,cursor,kiro
|
|
90
|
+
|
|
91
|
+
# Uninstall
|
|
92
|
+
nodriver-mcp uninstall claude
|
|
93
|
+
|
|
94
|
+
# List all supported clients
|
|
95
|
+
nodriver-mcp --list-clients
|
|
96
|
+
|
|
97
|
+
# Print MCP config JSON (for manual setup)
|
|
98
|
+
nodriver-mcp --config
|
|
99
|
+
|
|
100
|
+
# Project-level config (writes to .cursor/mcp.json, .mcp.json, etc.)
|
|
101
|
+
nodriver-mcp install --scope project
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Supported clients:** Claude Desktop, Claude Code, Cursor, Windsurf, Codex, Gemini CLI, Copilot CLI, Kiro, VS Code, Cline, Roo Code, Amazon Q, Warp, Opencode, Trae.
|
|
105
|
+
|
|
106
|
+
> The Claude Code VS Code extension shares Claude Code's config (`~/.claude.json`), so installing to `claude-code` covers both the CLI and the extension.
|
|
107
|
+
|
|
108
|
+
### Manual config
|
|
109
|
+
|
|
110
|
+
If you'd rather paste it yourself, this works in any MCP client (`claude_desktop_config.json`, `~/.claude.json`, `.cursor/mcp.json`, `.mcp.json`, …):
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
{
|
|
114
|
+
"mcpServers": {
|
|
115
|
+
"nodriver": {
|
|
116
|
+
"command": "uvx",
|
|
117
|
+
"args": ["nodriver-mcp"]
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Environment Variables
|
|
124
|
+
|
|
125
|
+
| Variable | Description | Default |
|
|
126
|
+
|----------|-------------|---------|
|
|
127
|
+
| `NODRIVER_HEADLESS` | Headless mode (`true`/`false`) | `false` |
|
|
128
|
+
| `NODRIVER_USER_DATA_DIR` | Explicit persistent Chrome profile dir (overrides the default) | Ephemeral temp profile, auto-deleted per session |
|
|
129
|
+
| `NODRIVER_BROWSER_PATH` | Chrome executable path | Auto-detected |
|
|
130
|
+
| `NODRIVER_PROXY` | Proxy server address | None |
|
|
131
|
+
| `NODRIVER_ENABLE_TRANSLATE` | Set `true` to re-enable Chrome's Google Translate popup | Disabled |
|
|
132
|
+
| `NODRIVER_ENABLE_EXTENSIONS` | Set `true` to allow externally-installed Chrome extensions (and their prompts) | Disabled |
|
|
133
|
+
|
|
134
|
+
By default the browser starts clean for automation: the **Google Translate popup is suppressed** and **externally-installed Chrome extensions are blocked** (so you don't get "an extension requires your attention" prompts). Re-enable either via the env vars above **or at runtime with the `set_browser_flags` tool** — which can also set **any other Chrome launch flags** (e.g. `--lang=de-DE`, `--window-size=1280,800`) via its `extra_args` parameter. The browser also **auto-recovers** if Chrome is closed or crashes between calls — tools relaunch it instead of failing.
|
|
135
|
+
|
|
136
|
+
Chrome also starts on `about:blank` rather than the New Tab page, so the NTP's own Google requests never show up in `list_network_requests`, and `new_page` **reuses that empty startup tab** instead of leaving a stray blank page behind.
|
|
137
|
+
|
|
138
|
+
## Extensions
|
|
139
|
+
|
|
140
|
+
`manage_extensions` handles extensions at runtime:
|
|
141
|
+
|
|
142
|
+
- `manage_extensions("list")` — extensions installed in the active profile (name, version, id) plus the current state
|
|
143
|
+
- `manage_extensions("on")` / `("off")` — the master switch (`--disable-extensions`); restarts Chrome. It covers unpacked extensions too, so `"off"` really means off
|
|
144
|
+
- `manage_extensions("load", path)` / `("unload", path)` — unpacked extensions from a folder
|
|
145
|
+
|
|
146
|
+
To use an extension permanently, switch to a persistent profile, install it once from the Chrome Web Store in that browser, and turn extensions on — it then loads on every launch.
|
|
147
|
+
|
|
148
|
+
> **Unpacked extensions need Chromium or Chrome for Testing.** Official Chrome builds dropped `--load-extension` in v137, and as of Chrome 151 neither `--enable-unsafe-extension-debugging` nor disabling `DisableLoadExtensionCommandLineSwitch` brings it back — the flag is accepted and the extension is silently never registered. `manage_extensions` detects a branded build and says so instead of pretending it worked. Point `NODRIVER_BROWSER_PATH` at Chromium / Chrome for Testing if you need unpacked loading.
|
|
149
|
+
|
|
150
|
+
## Profiles & running multiple instances at once
|
|
151
|
+
|
|
152
|
+
By default every server instance launches Chrome with a **fresh temporary profile** that nodriver creates and deletes automatically. That means you can run nodriver from **Claude Desktop, Claude Code and the VS Code extension at the same time** — each gets its own isolated Chrome, and they never fight over a shared profile. No configuration, no detection logic, nothing to clean up.
|
|
153
|
+
|
|
154
|
+
When you want to **reuse a login across sessions**, create a named persistent profile and switch to it:
|
|
155
|
+
|
|
156
|
+
- `list_profiles` — list persistent profiles and show the active one
|
|
157
|
+
- `create_profile(name, activate=false)` — create a reusable profile
|
|
158
|
+
- `use_profile(name)` — switch to a persistent profile (`""`/`"temp"` returns to ephemeral)
|
|
159
|
+
- `use_temp_profile` — switch back to a fresh ephemeral profile
|
|
160
|
+
- `delete_profile(name)` — remove a persistent profile
|
|
161
|
+
|
|
162
|
+
Persistent profiles live under `~/.nodriver-mcp/profiles/<name>`. You can still force a fixed profile globally with the `NODRIVER_USER_DATA_DIR` env var.
|
|
163
|
+
|
|
164
|
+
## Tools (57)
|
|
165
|
+
|
|
166
|
+
Network collection is enabled automatically on each tab. Console collection is opt-in: call `enable_console_collection` when you want `list_console_messages` / `get_console_message` to start collecting events. This keeps `Runtime.enable()` disabled by default for sites that detect attached debuggers.
|
|
167
|
+
|
|
168
|
+
For mobile-only sites, pass `device` directly to `new_page(...)` or `navigate_page(...)` so the first real request already carries mobile signals.
|
|
169
|
+
|
|
170
|
+
`click` and `click_at` send **real CDP input events**, so the page sees `isTrusted=true`. A scripted click (`element.click()` plus synthetic events, `isTrusted=false`) is used only where real input cannot be delivered — on a touch-emulated target, or after the CDP click times out — and the response says when that happened, so a detectable click is never silent.
|
|
171
|
+
|
|
172
|
+
| Category | Tools |
|
|
173
|
+
|----------|-------|
|
|
174
|
+
| **Input automation (10)** | `click` · `click_at` · `hover` · `fill` · `fill_form` · `type_text` · `press_key` · `drag` · `upload_file` · `handle_dialog` |
|
|
175
|
+
| **Navigation (10)** | `navigate_page` · `new_page` · `close_page` · `close_browser` · `list_pages` · `select_page` · `wait_for` · `wait_for_selector` · `scroll_page` · `scroll_to_selector` |
|
|
176
|
+
| **Snapshots & debugging (10)** | `take_screenshot` · `take_snapshot` · `get_page_content` · `query_selector` · `evaluate_script` · `save_pdf` · `enable_console_collection` · `disable_console_collection` · `list_console_messages` · `get_console_message` |
|
|
177
|
+
| **Network monitoring (3)** | `list_network_requests` · `get_network_request` · `block_resources` |
|
|
178
|
+
| **Device emulation (4)** | `emulate` · `emulate_device` · `reset_emulation` · `resize_page` |
|
|
179
|
+
| **Performance (3)** | `performance_start_trace` · `performance_stop_trace` · `take_memory_snapshot` |
|
|
180
|
+
| **Cookies & storage (5)** | `get_cookies` · `set_cookie` · `clear_cookies` · `get_local_storage` · `set_local_storage` |
|
|
181
|
+
| **Session management (3)** | `save_session` · `load_session` · `list_sessions` |
|
|
182
|
+
| **Profiles & browser (7)** | `list_profiles` · `create_profile` · `use_profile` · `use_temp_profile` · `delete_profile` · `set_browser_flags` · `manage_extensions` |
|
|
183
|
+
| **Anti-detection helpers (2)** | `cf_verify` · `bypass_insecure_warning` |
|
|
184
|
+
|
|
185
|
+
📖 **[Full tool reference →](docs/TOOLS.md)** — every tool with its exact parameters, types, defaults and enum values, generated straight from the live schemas.
|
|
186
|
+
|
|
187
|
+
## Built for the agent that calls it
|
|
188
|
+
|
|
189
|
+
An MCP tool is only as good as what the model can see of it. Most servers hand over a name, a sentence, and untyped parameters — leaving the agent to guess whether it's `type="url"` or `type="goto"`, and burning a failed call to find out.
|
|
190
|
+
|
|
191
|
+
Here, the schema does that work:
|
|
192
|
+
|
|
193
|
+
- **Every parameter has a description in the schema itself** — not buried in a prose blob the client may never show. All 57 tools, all parameters, no exceptions (there's a test for it).
|
|
194
|
+
- **Fixed-value parameters are real enums.** `navigate_page(type=…)` advertises exactly `url`, `back`, `forward`, `reload`. A wrong value is rejected by validation before it ever reaches Chrome, instead of returning an error the agent has to interpret.
|
|
195
|
+
- **Numeric and array bounds are declared** — `quality` is 0–100, `wait_for(text=…)` requires at least one entry.
|
|
196
|
+
- **Structured parameters are typed.** `fill_form` publishes `{uid, value}` rather than an opaque `list[dict]`.
|
|
197
|
+
- **Every tool declares behaviour hints** (`readOnlyHint`, `destructiveHint`, `idempotentHint`). Clients use these to group permissions — so a client can auto-approve `take_snapshot` while still prompting for `delete_profile`.
|
|
198
|
+
- **Descriptions say when *not* to use a tool**, and point at the better one. `take_screenshot` tells the model to prefer `take_snapshot`; `click_at` points back to `click`.
|
|
199
|
+
|
|
200
|
+
## Comparison with chrome-devtools-mcp
|
|
201
|
+
|
|
202
|
+
| Feature | chrome-devtools-mcp | nodriver-mcp-server |
|
|
203
|
+
|---------|---------------------|---------------------|
|
|
204
|
+
| Browser backend | Puppeteer (ChromeDriver) | nodriver (direct CDP) |
|
|
205
|
+
| WebDriver fingerprint | ❌ Exposed | ✅ None |
|
|
206
|
+
| `navigator.webdriver` | ❌ `true` | ✅ `undefined` |
|
|
207
|
+
| Cloudflare bypass | ❌ | ✅ Built-in `cf_verify` |
|
|
208
|
+
| Install method | npx | uvx / pip |
|
|
209
|
+
| Language | TypeScript / Node.js | Python |
|
|
210
|
+
| Tool coverage | 29 tools | 57 tools |
|
|
211
|
+
| Per-parameter schema docs | partial | ✅ all 57 tools |
|
|
212
|
+
| Tool behaviour hints | ❌ | ✅ read-only / destructive |
|
|
213
|
+
|
|
214
|
+
Tools not implemented: `performance_analyze_insight` (needs the DevTools frontend trace parser), `lighthouse_audit` (needs the Lighthouse Node API), `screencast_start/stop` (needs ffmpeg + Puppeteer), extension management (experimental).
|
|
215
|
+
|
|
216
|
+
## Use cases
|
|
217
|
+
|
|
218
|
+
- **Scrape sites behind Cloudflare / anti-bot** (DataDome, PerimeterX, hCaptcha challenges) without being fingerprinted or blocked.
|
|
219
|
+
- **Let an AI agent browse the real web** — Claude, Cursor, Windsurf and other LLM agents can log in, fill forms, click, read pages, and screenshot.
|
|
220
|
+
- **Automate authenticated workflows** and reuse the login across sessions with persistent profiles.
|
|
221
|
+
- **LLM-driven web research & data extraction** using compact accessibility-tree snapshots instead of brittle screenshots.
|
|
222
|
+
- **End-to-end / QA testing** with device emulation, network + console inspection, and performance traces.
|
|
223
|
+
- An **undetected alternative to Playwright, Puppeteer and Selenium** for agentic browsing.
|
|
224
|
+
|
|
225
|
+
## FAQ
|
|
226
|
+
|
|
227
|
+
**Is this an undetected alternative to chrome-devtools-mcp?**
|
|
228
|
+
Yes. It exposes the same tool surface but drives Chrome through nodriver (direct CDP), so `navigator.webdriver` is `undefined` and there are no WebDriver/CDP fingerprints for anti-bot systems to detect.
|
|
229
|
+
|
|
230
|
+
**Can it bypass Cloudflare?**
|
|
231
|
+
It ships a `cf_verify` tool that solves the Cloudflare "verify you are human" challenge, and its undetected profile avoids most bot checks. (No tool can guarantee bypassing every protection.)
|
|
232
|
+
|
|
233
|
+
**Which clients are supported?**
|
|
234
|
+
One command installs it into 15+ MCP clients: Claude Desktop, Claude Code, Cursor, Windsurf, Codex, Gemini CLI, Copilot CLI, Kiro, VS Code, Cline, Roo Code, Amazon Q, Warp, Opencode, Trae.
|
|
235
|
+
|
|
236
|
+
**Can I run it in several clients at the same time?**
|
|
237
|
+
Yes. Each instance uses its own ephemeral Chrome profile by default, so Claude Desktop, Claude Code and the VS Code extension can all use nodriver **simultaneously** without colliding.
|
|
238
|
+
|
|
239
|
+
**Headless or visible browser?**
|
|
240
|
+
A real Chrome window by default; set `NODRIVER_HEADLESS=true` for headless.
|
|
241
|
+
|
|
242
|
+
**How do I keep a login between sessions?**
|
|
243
|
+
Create a persistent profile with `create_profile` and switch to it with `use_profile`, or use `save_session` / `load_session`.
|
|
244
|
+
|
|
245
|
+
**Does it work on Windows / macOS / Linux?**
|
|
246
|
+
Yes, all three. Tested on Windows 11 with Chrome 150 and Python 3.12.
|
|
247
|
+
|
|
248
|
+
## Changelog
|
|
249
|
+
|
|
250
|
+
See [CHANGES.md](CHANGES.md). Highlights: ephemeral-by-default Chrome profiles so multiple instances run at once (+ named persistent profiles), migrated to upstream `nodriver 0.50.3` (Chrome 150 verified), and fixed several previously-broken tools — `fill`/`fill_form`, `evaluate_script` with element args, `select_page` tab switching, `press_key` modifier chords (Ctrl+A/C/V), network/console lookup indexing, and Windows installer crashes.
|
|
251
|
+
|
|
252
|
+
## Credits
|
|
253
|
+
|
|
254
|
+
Based on [`nodriver-mcp`](https://github.com/Saber-CC/nodriver-mcp) by **Saber-CC** (MIT). Browser backend by [`nodriver`](https://github.com/ultrafunkamsterdam/nodriver) (ultrafunkamsterdam). Tool surface mirrors [`chrome-devtools-mcp`](https://github.com/ChromeDevTools/chrome-devtools-mcp).
|
|
255
|
+
|
|
256
|
+
## License
|
|
257
|
+
|
|
258
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "nodriver-mcp"
|
|
3
|
+
version = "1.7.0"
|
|
4
|
+
description = "Undetected Chrome automation MCP server powered by nodriver — a stealth, anti-bot-resistant alternative to chrome-devtools-mcp for Claude, Cursor and other AI agents"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.12"
|
|
7
|
+
authors = [
|
|
8
|
+
{ name = "Andre Solbach" },
|
|
9
|
+
]
|
|
10
|
+
maintainers = [
|
|
11
|
+
{ name = "Andre Solbach" },
|
|
12
|
+
]
|
|
13
|
+
keywords = [
|
|
14
|
+
"mcp", "model-context-protocol", "mcp-server", "nodriver", "chrome",
|
|
15
|
+
"browser-automation", "web-scraping", "undetected", "anti-bot",
|
|
16
|
+
"cloudflare-bypass", "claude", "cursor", "ai-agent", "llm",
|
|
17
|
+
"chrome-devtools-mcp", "playwright-alternative", "puppeteer-alternative",
|
|
18
|
+
]
|
|
19
|
+
classifiers = [
|
|
20
|
+
"Development Status :: 4 - Beta",
|
|
21
|
+
"Intended Audience :: Developers",
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
]
|
|
25
|
+
dependencies = [
|
|
26
|
+
"mcp>=1.26.0,<2",
|
|
27
|
+
# Chrome 146+ CDP fixes (sameParty removal, localNetworkAccessRequestPolicy
|
|
28
|
+
# rename) that once required the Saber-CC fork are upstream as of 0.50.x.
|
|
29
|
+
# Verified working against Chrome 150.
|
|
30
|
+
"nodriver>=0.50.3",
|
|
31
|
+
"pillow>=12.1.1",
|
|
32
|
+
"tomli-w>=1.0.0",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
[project.urls]
|
|
36
|
+
Homepage = "https://github.com/andresolbach/nodriver-mcp-server"
|
|
37
|
+
Repository = "https://github.com/andresolbach/nodriver-mcp-server"
|
|
38
|
+
Issues = "https://github.com/andresolbach/nodriver-mcp-server/issues"
|
|
39
|
+
|
|
40
|
+
[build-system]
|
|
41
|
+
requires = ["setuptools>=68.0"]
|
|
42
|
+
build-backend = "setuptools.build_meta"
|
|
43
|
+
|
|
44
|
+
[tool.setuptools.packages.find]
|
|
45
|
+
where = ["src"]
|
|
46
|
+
|
|
47
|
+
[project.scripts]
|
|
48
|
+
nodriver-mcp = "nodriver_mcp.cli:main"
|
|
49
|
+
|
|
50
|
+
[dependency-groups]
|
|
51
|
+
dev = [
|
|
52
|
+
"pytest>=8.0",
|
|
53
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""nodriver-mcp: Undetected Chrome automation MCP server."""
|