Undetectable browser automation for AI agents via the Model Context Protocol.
Project description
Stealth Chrome DevTools MCP
Undetectable browser automation for AI agents via the Model Context Protocol.
A self-contained stealth Chrome DevTools MCP server with smart profile management, anti-detection stealth arg filtering, and robust process lifecycle handling. Built on nodriver (CDP-based) for full anti-bot evasion.
Demos
Cloudflare Turnstile Bypass
https://github.com/user-attachments/assets/c4de61ae-6878-4fff-9bfd-65cdd4fadc2f
Persistent Login Sessions
https://github.com/user-attachments/assets/f81fc0c2-9233-48cd-8a9d-2577b1d33d57
Key Features
- Undetectable by anti-bot systems — Cloudflare, DataDome, PerimeterX, etc.
- Smart profile management — master/snapshot/clone strategy preserves logins across sessions
- Stealth arg filtering — automatically strips 30+ detectable Chrome flags (Puppeteer/Playwright signatures, automation markers)
- Multi-instance support — spawn and manage multiple browsers simultaneously
- Auto-suffix busy profiles —
github-sessionauto-becomesgithub-session-2when occupied - Orphan recovery — safely cleans up leaked browser processes without killing live ones
- Session persistence — cloned profiles carry cookies, logins, and Web Data from master
- Zero idle timeout — browsers stay alive until explicitly closed
- Full CDP access — DOM manipulation, network interception, JavaScript execution, screenshots
Quick Start
Add to your MCP config (claude_desktop_config.json, .claude/settings.json, etc.):
{
"mcpServers": {
"stealth-chrome-devtools-mcp": {
"command": "uvx",
"args": ["stealth-chrome-devtools-mcp==2.0.1"]
}
}
}
Or install via pip:
pip install stealth-chrome-devtools-mcp==2.0.1
Local Development
{
"mcpServers": {
"stealth-chrome-devtools-mcp": {
"command": "uv",
"args": [
"--directory", "/path/to/stealth-chrome-devtools-mcp",
"run", "stealth-chrome-devtools-mcp"
]
}
}
}
How It Works
Browser Profile Strategy
C:\stealth-mcp-browser-sessions\
master/ # Your primary Chrome profile (logins, cookies, extensions)
master-snapshot/ # Safe copy refreshed while master is closed
sessions/ # Cloned profiles for concurrent use
github-session/
github-session-2/ # Auto-suffixed when github-session is busy
spawn_browser()uses the master profile when available- Before opening master, the server refreshes
master-snapshot - When master is busy, a clone is created from the snapshot
- Clones carry all cookies, logins, and session data
- Stale snapshots are auto-refreshed when auth files change
Clones exclude regenerable Chrome caches, so each is a few MB rather than
multiple GB. Disposable auto-clones are deleted on close, and a storage cap
(STEALTH_MCP_CLONE_STORAGE_CAP_GB, default 10 GB) reclaims the oldest idle
clones if any ever leak — so sessions/ stays bounded. Cap eviction is
recoverable: an evicted clone is moved into sessions/.trash/ and only
purged after a retention window (STEALTH_MCP_CLONE_TRASH_RETENTION_HOURS,
default 24 h), so a mistaken eviction can be restored rather than lost.
Named profiles you create explicitly (e.g. github-session) persist and are
never deleted. But even a "persistent" profile is ~98% regenerable (caches plus
Chrome's multi-GB on-device AI model). So when sessions/ exceeds
STEALTH_MCP_BROWSER_SESSION_STORAGE_CAP_GB (default 20 GB), the largest idle named
profiles are trimmed of those regenerable dirs while every login is
preserved — Chrome rebuilds them on next launch. In-use profiles are never
touched.
Shared-machine note: the browser-session root defaults to
C:\stealth-mcp-browser-sessions(drive root), which holds your logged-in cookies and session data. On a single-user machine this is fine. On a shared multi-user Windows box, other local users may be able to read it — pointSTEALTH_MCP_BROWSER_SESSION_ROOTat a location inside your user profile (e.g.%LOCALAPPDATA%\stealth-mcp) so the OS user ACLs protect it.
Stealth Arg Filtering
The server automatically strips Chrome flags that would compromise stealth:
| Category | Examples | Why Stripped |
|---|---|---|
| Automation signals | --enable-automation, --test-type |
Sets navigator.webdriver=true |
| Fingerprint leaks | --disable-gpu, --disable-webgl |
Detectable via WebGL/canvas probes |
| Puppeteer defaults | --disable-backgrounding-occluded-windows |
Bot signature fingerprint |
| Playwright defaults | --password-store=basic, --use-mock-keychain |
Bot signature fingerprint |
Stripped args are reported in spawn_diagnostics.stealth_args_stripped.
Orphan Recovery
On server restart, the process cleanup system:
- Identifies browser processes from previous sessions via
create_timetracking - Only kills processes started before the current server session
- Never kills browsers spawned during the current run
- Safely handles
psutil.AccessDeniedon Windows elevated processes
Usage Examples
# Spawn with default master profile
spawn_browser()
# Named session with login persistence
spawn_browser(user_data_dir="github-session")
# Same name while first is open → auto-suffixes to github-session-2
spawn_browser(user_data_dir="github-session")
# Headless with stealth (bad args auto-stripped)
spawn_browser(headless=True, browser_args=["--enable-automation"])
# → stealth_args_stripped: ["--enable-automation stripped: sets navigator.webdriver=true"]
MCP Tools
| Tool | Description |
|---|---|
spawn_browser |
Launch a new stealth browser instance |
navigate |
Navigate to a URL |
take_screenshot |
Capture page screenshot |
execute_script |
Run JavaScript in page context |
query_elements |
Find DOM elements by CSS selector |
click_element |
Click on an element |
type_text |
Type text into an input |
get_page_content |
Get page HTML content |
list_instances |
List all active browser instances |
close_instance |
Close a specific browser |
list_network_requests |
View intercepted network traffic |
get_cookies / set_cookie |
Manage browser cookies |
94 tools across 11 sections — the count is derived from the live tool registry, never hand-maintained. See the full navigation map →.
That is what the server serves, which is not the same as what the release
gate proves. At the release SHA in the evidence ledger, 3 of those 94 are
release-qualified: asserted end-to-end over the real stdio transport a client
actually speaks. The rest are driven against real Chrome by the E2E suite but
through an in-process seam, so they are served-unqualified at the wire — tested,
not proved there. RELEASE_CONTRACT.md lists the state of
each tool and is the only source for those numbers.
Testing
# Unit tests only (no Chrome needed)
uv run pytest -m "not integration"
# All tests (needs Chrome installed)
uv run pytest
# Verbose with short tracebacks
uv run pytest -v --tb=short
If your checkout path contains spaces or an
&,uv run pytestfails withFailed to canonicalize script path— use the venv Python directly:.venv\Scripts\python.exe -m pytest -m "not integration". See CONTRIBUTING.md for the full test/gate workflow.
A comprehensive suite covers stealth arg filtering, profile resolution, orphan recovery, storage-cap sweeps, the ops CLI, and full browser integration.
Environment Variables
All optional. Defaults work for normal use.
| Variable | Default | Purpose |
|---|---|---|
STEALTH_MCP_BROWSER_SESSION_ROOT |
C:\stealth-mcp-browser-sessions (Win) / ~/.stealth-mcp-browser-sessions (Unix) |
Base folder for profiles |
BROWSER_MASTER_USER_DATA_DIR |
<root>/master |
Master Chrome profile path |
BROWSER_MASTER_SNAPSHOT_DIR |
<root>/master-snapshot |
Snapshot clone source |
BROWSER_PROFILE_CLONE_ROOT |
<root>/sessions |
Folder for profile copies |
BROWSER_PROFILE_REFRESH_DAYS |
7 |
Refresh copies after N days (0 = disable) |
STEALTH_MCP_CLONE_STORAGE_CAP_GB |
10 |
Cap on total auto-clone storage; oldest idle clones are reclaimed when exceeded (0 = disable). Named profiles and in-use clones are never touched. |
STEALTH_MCP_BROWSER_SESSION_STORAGE_CAP_GB |
20 |
Cap on total sessions/ storage; when exceeded, the largest idle named profiles are trimmed of regenerable cache/model dirs — logins kept (0 = disable). (Renamed from STEALTH_MCP_SESSION_STORAGE_CAP_GB; update your config — the old name is no longer read.) |
STEALTH_MCP_CLONE_TRASH_RETENTION_HOURS |
24 |
How long a cap-evicted clone stays recoverable in sessions/.trash/ before purge (0 = purge on next sweep). |
STEALTH_MCP_CLONE_OUTPUT_DIR |
~/.stealth-mcp/element_clones |
Where screenshots, large-response spills, and element-clone files are written. Kept in a per-user dir (never inside the installed package) so a read-only site-packages can't break captures. |
BROWSER_IDLE_TIMEOUT |
0 |
Idle cleanup timeout (0 = disabled) |
STEALTH_CHROME_PROFILE_KEY |
unset | Force a stable clone key |
STEALTH_MCP_CLIENT_ROOTS_TIMEOUT_SECONDS |
5 |
Deadline for the roots/list request the auto-clone path sends to the MCP client to name a clone. MCP roots is optional, so a client may never answer; on expiry the clone name falls back to CODEX_WORKSPACE/CLAUDE_PROJECT_DIR/PWD/cwd (0 = never ask). |
STEALTH_BROWSER_DEBUG |
false |
Enable debug logging |
CLI
Installs a stealth-chrome-devtools ops command for managing the server and its
disk usage. (This is for ops — to drive a browser, use the MCP server or its
HTTP backend.)
These four only read and preview — they change nothing, and the test suite runs them on every commit, so they are known to work:
stealth-chrome-devtools status
stealth-chrome-devtools profiles
stealth-chrome-devtools cleanup
stealth-chrome-devtools cleanup --browser-session-cap-gb 12
status reports whether the backend is up plus the browser-session root and both
caps; profiles lists profiles with size / role / in-use; cleanup previews the
reclaimable disk (dry run), and --browser-session-cap-gb previews it at a
tighter cap.
These are not auto-executed — --apply deletes, serve does not return, and
doctor needs Chrome installed:
stealth-chrome-devtools cleanup --apply # actually reclaim
stealth-chrome-devtools doctor # check Chrome / environment
stealth-chrome-devtools serve --http --port 19222 # start the server
cleanup deletes idle auto-clones over the clone cap and trims idle named
profiles down to their session state — logins kept — over the browser-session cap. It
is a dry run unless you pass --apply, never touches in-use profiles, and
uses the same selectors as the automatic sweep, so the preview matches --apply.
Preparing the Master Profile
- Start the MCP server
- Call
spawn_browser()withoutuser_data_dir - Sign in to your accounts in the browser that opens
- Close it — future sessions use this profile or clone from it
Requirements
- Python 3.11+
- Chrome, Chromium, or Microsoft Edge
- uv (recommended) or pip
Error Reporting (opt-in)
Error reporting via Sentry is available but off by default. No data is collected unless you explicitly enable it.
To opt in (helps us diagnose issues when you need support):
pip install stealth-chrome-devtools-mcp[sentry]
# Add to your .env or export in your shell:
SENTRY_DSN=https://3206541bdab9246f00d7099e692e2ee2@sentry.devino.ca/34
To disable, simply unset SENTRY_DSN or remove it from your .env.
Development setup
git clone https://github.com/DevinoSolutions/stealth-chrome-devtools-mcp
cd stealth-chrome-devtools-mcp
uv sync --extra dev --extra test # install linters + test deps
npm install # arm husky pre-commit/pre-push hooks
The six quality gates run automatically on every commit: ruff format, ruff check, ty check, vulture, suppression-owner check, file-budget check. Unit tests run on pre-push.
Documentation
- CLAUDE.md — navigation map of the source tree + glossary + conventions
- DESIGN.md — architecture invariants and the why behind them
- RUNBOOK.md — operating the backend: verbs, logs, recovery, MCP smoke path
- CONTRIBUTING.md — clone → install → test, the quality gate, conventions
License
See LICENSE.
Built by Devino Solutions
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file stealth_chrome_devtools_mcp-2.0.1.tar.gz.
File metadata
- Download URL: stealth_chrome_devtools_mcp-2.0.1.tar.gz
- Upload date:
- Size: 841.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
df448b7da50a4377fbabecd162395afc8ea967897d6b725e30eae010e5b38579
|
|
| MD5 |
47634a3f7e1c5b5015bc4ba600e89ae6
|
|
| BLAKE2b-256 |
b7f8a185df0a6ffcd8a2dd673e810191c3460285c629aed4677716c5ac44a59a
|
Provenance
The following attestation bundles were made for stealth_chrome_devtools_mcp-2.0.1.tar.gz:
Publisher:
publish.yml on DevinoSolutions/stealth-chrome-devtools-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
stealth_chrome_devtools_mcp-2.0.1.tar.gz -
Subject digest:
df448b7da50a4377fbabecd162395afc8ea967897d6b725e30eae010e5b38579 - Sigstore transparency entry: 2299217319
- Sigstore integration time:
-
Permalink:
DevinoSolutions/stealth-chrome-devtools-mcp@e1ec8251cd781b6525fcf9b8f08e8e99ae19d7cc -
Branch / Tag:
refs/tags/v2.0.1 - Owner: https://github.com/DevinoSolutions
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e1ec8251cd781b6525fcf9b8f08e8e99ae19d7cc -
Trigger Event:
push
-
Statement type:
File details
Details for the file stealth_chrome_devtools_mcp-2.0.1-py3-none-any.whl.
File metadata
- Download URL: stealth_chrome_devtools_mcp-2.0.1-py3-none-any.whl
- Upload date:
- Size: 202.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
70ea413a257cd4631d852c087e9de17777d23e8876b1bb1a1d76ef72d4b5c4b9
|
|
| MD5 |
85ae00ee0a7a4a9539038a55c9a74d45
|
|
| BLAKE2b-256 |
0d3a84b335eab83c4e7488e9918253d72ad928972f0028f81cf961f949203320
|
Provenance
The following attestation bundles were made for stealth_chrome_devtools_mcp-2.0.1-py3-none-any.whl:
Publisher:
publish.yml on DevinoSolutions/stealth-chrome-devtools-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
stealth_chrome_devtools_mcp-2.0.1-py3-none-any.whl -
Subject digest:
70ea413a257cd4631d852c087e9de17777d23e8876b1bb1a1d76ef72d4b5c4b9 - Sigstore transparency entry: 2299217368
- Sigstore integration time:
-
Permalink:
DevinoSolutions/stealth-chrome-devtools-mcp@e1ec8251cd781b6525fcf9b8f08e8e99ae19d7cc -
Branch / Tag:
refs/tags/v2.0.1 - Owner: https://github.com/DevinoSolutions
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e1ec8251cd781b6525fcf9b8f08e8e99ae19d7cc -
Trigger Event:
push
-
Statement type: