MCP browser bridge that gives AI clients full access to a live browser environment.
Project description
mithwire-mcp
🚀 MCP server that gives AI clients full access to a live Chromium browser environment.
Your AI client launches fresh, isolated browser sessions — ephemeral by default, or backed by a persistent managed profile when you need a durable logged-in identity. It is built for autonomous automation, developer workflows, and production-style browser operations, powered by mithwire.
Demo Video
🌟 Product Highlights
mithwire-mcp turns browser automation into a reliable MCP service your agents can trust in real workflows, not just demos.
🧠 Intelligent Chromium orchestration
- Launch fresh sessions instantly with
session_start— always a brand-new, isolated browser process. - One simple choice: ephemeral (default) or a persistent managed
profile. No flaky attach/clone paths to reason about. - Run with confidence using robust session lifecycle controls (
start,list,get,stop,stop_all) and per-session action locking. - Stay out of the user's way: the MCP never touches, attaches to, or tears down a browser it didn't spawn.
🤖 Built for autonomous agents and fast-moving teams
- Give agents deterministic control over navigate/query/click/type/wait/evaluate/screenshot flows.
- Ship faster with first-class support for E2E prototyping, scraping pipelines, regression checks, and interactive debugging.
- Get live operational visibility with console output, request metadata, and CDP-level network capture.
- Reduce flaky runs and shorten feedback loops across development and QA.
👤 Durable browser identity and session state
- Centralize reusable browser state under one roof:
profiles/andconfigs/. - A managed
profilepersists its own cookies and storage natively across runs — no separate cookie bookkeeping required. - Fine-tune launch behavior with configurable browser flags, executable paths, headless/sandbox settings, and first-class proxy support (incl. authenticated HTTP/HTTPS proxies).
- Preserve realistic, persistent browser identity across sessions for multi-account and high-continuity automation.
🕵️ Stealth foundation with mithwire + CDP
- Powered by
mithwire: a maintained no-WebDriver/no-Selenium Chromium automation runtime. - Includes anti-bot oriented capabilities, including Cloudflare Turnstile solving through
browser_solve_cloudflare. - Control the full identity: IP (authenticated proxy via local relay), location (proxy-aligned timezone), language, and device profile (fingerprint spoofing) — kept internally consistent across workers and headers.
- WebRTC leak protection stops the host's real IP from leaking around the proxy.
- Built on direct CDP control for low-level precision, observability, and flexibility.
- Better suited for modern websites where reliability under anti-automation pressure matters.
Quick Start (recommended)
1) Install prerequisites
- Python
>=3.10(Python3.14+is supported with the latestmithwire) - A Chromium-based browser installed (Chrome, Brave or Edge)
- Optional but recommended:
pipx(for easy isolated CLI installs)
Install pipx (optional, recommended) on macOS:
brew install pipx
pipx ensurepath
Install pipx (optional, recommended) on Linux:
python3 -m pip install --user pipx
python3 -m pipx ensurepath
Install pipx (optional, recommended) on Windows (PowerShell):
py -m pip install --user pipx
py -m pipx ensurepath
2) Install mithwire-mcp
Option A (recommended): install with pipx
pipx install "git+https://github.com/codeisalifestyle/mithwire.git#subdirectory=packages/mithwire-mcp"
Option B (no pipx): install in a dedicated virtual environment
python3 -m venv ~/.venvs/mithwire-mcp
source ~/.venvs/mithwire-mcp/bin/activate
pip install "git+https://github.com/codeisalifestyle/mithwire.git#subdirectory=packages/mithwire-mcp"
Note:
mithwire-mcplives inside themithwiremonorepo as of v0.2. The install URL points at thepackages/mithwire-mcpsubdirectory of that repo.
Verify:
mithwire-mcp --help
3) Add it to your MCP client
Most MCP-enabled clients accept a config shaped like this:
{
"mcpServers": {
"mithwire-mcp": {
"command": "mithwire-mcp",
"args": ["--transport", "stdio"]
}
}
}
If your client cannot find the command, use an absolute path:
# macOS / Linux
which mithwire-mcp
# Windows (PowerShell)
where.exe mithwire-mcp
Then set "command" to that full path.
If you used Option B, your command path is typically:
~/.venvs/mithwire-mcp/bin/mithwire-mcp
4) First-use test in your AI client
After reloading/restarting your AI client, ask it:
- "Call
session_startwith default settings." - "Call
browser_navigatetohttps://example.com." - "Call
browser_snapshot." - "Call
session_stop."
If these succeed, installation is complete.
Launching a session
The MCP always spawns a brand-new, isolated browser process. It never
attaches to, takes over, or shuts down a browser it didn't launch. There are no
"modes" to memorize — session_start has exactly two shapes:
| Goal | Call | What you get |
|---|---|---|
| Throwaway browser (default) | {} |
A fresh ephemeral browser with no saved state. Ideal for scraping and E2E. |
| Persistent identity | { "profile": "twitter_main" } |
A managed profile whose cookies/storage persist across runs. |
Everything else is an optional flag layered on top of those two:
| Option | Default | Purpose |
|---|---|---|
headless |
false (headful) |
Run without a visible window (e.g. CI). |
proxy |
none | Route traffic through an upstream proxy (see below). |
fingerprint |
none | Identity overrides — timezone, locale/languages, geo, user agent, platform, hardware, screen, WebGL (see below). |
webrtc_leak_protection |
auto |
Guard WebRTC against real-IP leaks: auto / filter / disable / off (see below). |
start_url |
none | Navigate here right after launch. |
cookie_file |
none | One-shot injection of cookies from a JSON file at launch. |
sandbox |
true |
Keep Chromium's sandbox on (recommended; --no-sandbox is easily bot-detected). |
launch_config |
default |
Apply a saved set of launch settings. |
Proxy support
proxy accepts several common spellings and normalizes them:
http://host:portorhttp://user:pass@host:port- the provider
scheme:host:port:user:passform socks5://host:port- an object:
{ "server": "http://host:port", "username": "...", "password": "...", "rotation_url": "https://api.provider.com/rotate?token=..." }
rotation_url is optional. It's a provider endpoint that rotates the upstream
exit IP when hit. The MCP stores it on the proxy object at launch; call
session_rotate_proxy to trigger a rotation — it hits the endpoint, waits a
short settle window, re-probes through the proxy to confirm the new egress,
and (by default) re-aligns the browser identity (timezone, locale, languages,
geolocation) to match. Any field you pinned via fingerprint at launch (or
session_set_fingerprint since) keeps winning over the proxy-derived default.
Rotation URLs frequently embed a secret token in their query string, so the
URL is redacted anywhere it appears in session metadata or logs (userinfo
and query are stripped to ?***); the literal URL stays in-memory only.
Authenticated HTTP/HTTPS proxies are fully supported. Rather than answering
the proxy challenge per request over CDP (which floods the event loop and stalls
heavy page loads), the MCP starts a small local authenticating relay:
Chromium is pointed at 127.0.0.1, and the relay injects the upstream
Proxy-Authorization header and pipes bytes through to the real proxy. The
browser never sees a 407. Unauthenticated HTTP/HTTPS and SOCKS proxies go
straight to --proxy-server. Authenticated SOCKS is rejected up front
(Chromium's --proxy-server can't carry SOCKS credentials) — use the provider's
HTTP/HTTPS endpoint instead.
Pre-launch proxy health check. A session that asks for a proxy is refused
before any browser is spawned if that proxy is unreachable or rejects the
credentials. The MCP issues a single absolute-form GET http://api.ipapi.is/
to the proxy (with Proxy-Authorization when present) and only proceeds on a
clean 2xx with parseable JSON. There is no fallback to the host's direct
connection — that would silently leak the real IP into login flows and
cross-contaminate any persistent profile. A bad proxy fails fast with an
actionable error (timeout / refused TCP / HTTP 407 etc.); the browser process
is never started.
Identity defaults aligned to the proxy egress. The same probe doubles as
the egress lookup: when a proxy is set, the session defaults its identity —
timezone, locale, languages, Accept-Language, and geolocation — to the
proxy's egress IP so the two never disagree. Anything explicitly set in
fingerprint={...} or in the profile's launch_overrides wins over the
proxy-derived default, so profiles can pin a stable identity (e.g. a fixed
language) and still use rotating proxies. SOCKS proxies get a TCP-only
liveness check, with timezone alignment falling back to the in-browser
ipapi.is lookup (no auto-derived language for SOCKS). The detected egress
(ip, timezone, city, country, country_code) is recorded in the
session metadata under proxy_exit.
Fingerprint / identity spoofing
Pass a fingerprint object to session_start (or apply one to a live session
with session_set_fingerprint) to control the identity the browser presents.
All fields are optional; anything unset is left untouched:
timezone_id,locale,languages,accept_languagelatitude,longitude,geo_accuracyuser_agent,platform,hardware_concurrency,device_memory(GB)screen—width,height,device_scale_factor,mobile,max_touch_pointswebgl_vendor,webgl_renderer
Overrides are applied at the engine level via CDP Emulation.* wherever
Chromium supports it, so they propagate to Web Workers and HTTP request
headers — not just the main document — keeping every signal internally
consistent (a mismatched override is worse than none). The handful of properties
with no CDP equivalent (navigator.deviceMemory, and the WebGL strings when
requested) fall back to injected JS.
Two consistency rules matter: keep overrides same-OS-family (don't claim a Windows UA on a macOS host), and if you spoof geo/timezone, back it with a matching proxy so the egress IP agrees.
WebRTC leak protection
WebRTC can open a STUN connection that reveals the host's real local and public
IPs directly, bypassing the proxy entirely (UDP isn't proxied) — the single
biggest de-anonymization leak for a proxied browser. The webrtc_leak_protection
option controls the guard:
| Mode | Behavior |
|---|---|
auto (default) |
Filter leaky ICE candidates when a proxy is set; otherwise leave WebRTC intact. |
filter |
Always drop public, non-egress ICE candidates and scrub SDP. |
disable |
Remove RTCPeerConnection entirely (no WebRTC at all). |
off |
No protection (real IP can leak). |
Verifying stealth
scripts/verify_mcp.py launches a real session (the same BridgeBrowser path the
MCP uses) against public bot-detection services and asserts the critical signals
are clean — useful as a regression check after touching launch/stealth/proxy code:
python3 scripts/verify_mcp.py --headless # deviceinfo + fingerprint
python3 scripts/verify_mcp.py --site deviceinfo
python3 scripts/verify_mcp.py --proxy "http://user:pass@host:port" # also checks TZ alignment
Cookies
A managed profile stores its cookies in Chromium's native cookie store, so
they persist automatically — there is nothing extra to manage. The only
separate cookie operations are injection (cookie_file at launch, or
browser_cookies_set at runtime) and export (browser_cookies_get /
browser_cookies_save).
Centralized browser state store
mithwire-mcp now keeps reusable browser state in one place:
- Default root:
~/.mithwire-mcp - Override with env var:
MITHWIRE_MCP_HOME=/custom/path - Override per server run:
mithwire-mcp --state-root /custom/path
Within that root:
profiles/stores persistent Chromium profile directories (user data dirs)configs/stores launch configs used bysession_start
session_start supports optional profile and launch_config inputs.
It resolves launch settings in this order:
- Built-in defaults
- Saved default launch config (
configs/default.json) - Profile-linked launch config (if profile defines one)
- Selected
launch_config(if provided) - Profile
launch_overrides - Explicit
session_startarguments
This lets your AI client map account-oriented tasks to stable browser identities (profile + cookies + launch settings) without repeatedly passing raw paths.
Development setup
mithwire-mcp is developed inside the mithwire uv workspace, so the engine and the MCP can be edited together with no pin-bumping.
git clone https://github.com/codeisalifestyle/mithwire.git
cd mithwire
uv sync # creates .venv at repo root, installs both packages editable
uv run pytest packages/mithwire-mcp/tests -q
uv run mithwire-mcp --transport stdio
Client config for this mode:
{
"mcpServers": {
"mithwire-mcp": {
"command": "/absolute/path/to/mithwire-mcp",
"args": ["--transport", "stdio"]
}
}
}
Core tools exposed
Session lifecycle
session_startsession_listsession_getsession_state_pathssession_profile_listsession_profile_getsession_profile_setsession_profile_deletesession_launch_config_listsession_launch_config_getsession_launch_config_setsession_launch_config_deletesession_set_fingerprintsession_rotate_proxysession_set_policysession_get_policysession_set_download_dirsession_trace_startsession_trace_stopsession_trace_getsession_trace_exportsession_trace_replaysession_stopsession_stop_all
Browser actions
browser_urlbrowser_navigatebrowser_backbrowser_forwardbrowser_reloadbrowser_tab_listbrowser_tab_newbrowser_tab_switchbrowser_tab_closebrowser_tab_currentbrowser_snapshotbrowser_querybrowser_clickbrowser_typebrowser_handle_dialogbrowser_set_file_inputbrowser_scrollbrowser_waitbrowser_wait_for_selectorbrowser_wait_for_urlbrowser_wait_for_textbrowser_wait_for_functionbrowser_wait_for_network_idlebrowser_htmlbrowser_console_messagesbrowser_network_requestsbrowser_network_capture_startbrowser_network_capture_getbrowser_network_capture_stopbrowser_network_capture_statusbrowser_downloadsbrowser_cookies_getbrowser_cookies_setbrowser_cookies_savebrowser_cookies_clearbrowser_storage_getbrowser_storage_setbrowser_storage_clearbrowser_take_screenshotbrowser_evaluatebrowser_solve_cloudflare
Project docs
- Architecture:
docs/architecture.md
Troubleshooting
- "command not found: mithwire-mcp"
- Run
pipx ensurepath, restart terminal and AI client, then retry. - Use absolute command path from
which mithwire-mcp.
- Run
- Python version mismatch
- Use a supported Python (
>=3.10) and reinstall/upgrade the package in your MCP environment.
- Use a supported Python (
- Browser fails to launch in restricted environments
- Try
session_startwithsandbox=false.
- Try
- MCP client does not show tools
- Confirm JSON syntax is valid.
- Confirm transport is
stdio. - Fully restart the AI client after editing MCP config.
Safety notes
- Use this only on sites and accounts where you are authorized.
- Respect website Terms of Service and local regulations.
- Be cautious with high-frequency automation.
Project details
Release history Release notifications | RSS feed
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 mithwire_mcp-0.1.0.tar.gz.
File metadata
- Download URL: mithwire_mcp-0.1.0.tar.gz
- Upload date:
- Size: 129.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.11 {"installer":{"name":"uv","version":"0.11.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f5903250ef3cb7179302d611e5cedabc1011bfb7a238997323e1ad7200ec7e48
|
|
| MD5 |
cd566986570bba46ec9d11bc75dd9ae6
|
|
| BLAKE2b-256 |
e1ad81590a9a3f7f0f8ea3d58083f3475a69d979df99788de3502d1e46410f81
|
File details
Details for the file mithwire_mcp-0.1.0-py3-none-any.whl.
File metadata
- Download URL: mithwire_mcp-0.1.0-py3-none-any.whl
- Upload date:
- Size: 97.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.11 {"installer":{"name":"uv","version":"0.11.11","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c7709ea981b08a20e9db181f641a5e821aa554a726068dce196df5c8058757f4
|
|
| MD5 |
bffdefe562ff9214be52229d4f695a2f
|
|
| BLAKE2b-256 |
92efff21aded98e24f96e67ca7877b1171c2401d6c5d93488ae1f1c87a07c871
|