mcp-camoufox
v0.11.1
Published
MCP server for stealth browser automation via Camoufox — 133 tools, plus a browserless TLS-impersonating HTTP path
Downloads
3,328
Maintainers
Readme
MCP Camoufox
The most feature-rich stealth browser MCP server. 133 tools for full browser control powered by Camoufox — a Firefox fork with C++ level anti-detection that bypasses Cloudflare, bot detection, and anti-automation.
One command. No Python. No manual setup. Everything auto-installs.
claude mcp add camoufox -- npx -y mcp-camoufox@latestWhat Can It Do?
- Login to Google, ChatGPT, GitHub — without getting blocked
- Fill forms, click buttons, type text, upload files
- Manage cookies, localStorage, sessions across visits
- Take screenshots, export PDFs, capture network traffic
- Work with multiple tabs, iframes, dialogs
- Execute JavaScript, inspect elements, scroll pages
- Scrape structured data (job listings, products) with auto-detected selectors
- All while being undetectable by anti-bot systems
Comparison
| MCP Server | Tools | Stealth | npx Install | Persistent Session | | --------------------------------------------------------------- | ------- | ------- | ----------- | ------------------ | | Chrome DevTools MCP | 30+ | No | Built-in | Yes | | whit3rabbit/camoufox-mcp | 1 | Yes | Yes | No | | redf0x1/camofox-mcp | 47 | Yes | Yes | Yes | | Sekinal/camoufox-mcp | 49 | Yes | No (clone) | Yes | | Playwright CLI | 60+ | No | Yes | Yes | | mcp-camoufox | 133 | Yes | Yes | Yes |
Competitor figures checked 19 Aug 2026: camofox-mcp counted by running tools/list against v1.15.0 from npm (it is npx-installable — an earlier version of this table wrongly said otherwise); the others are taken from their own READMEs.
Proven on Real Sites
| Site | Challenge | Result |
| ---------------------------------------- | --------------------------- | ---------------------------------------------------------------------------------- |
| 2captcha.com/demo/cloudflare-turnstile | Cloudflare Turnstile widget | ✅ "Success!" via click_turnstile() tool (proof) |
| bot.sannysoft.com | Firefox fingerprint tests | ✅ All green (proof) |
| browserscan.net/bot-detection | WebDriver/UA/CDP/Navigator | ✅ All categories "Normal" (proof) |
🎯 Cloudflare Turnstile → Success via click_turnstile()
click_turnstile() auto-detects the widget via 6 selector fallback (iframe[src*=challenges.cloudflare.com], [data-sitekey], .cf-turnstile, …), computes checkbox position (offset_x=30 from widget left), and clicks with a 3-step Bezier-like approach — combined with Camoufox's native humanize + disable_coop for cross-origin iframe click.
Scope: works on Interactive Turnstile (visible iframe widget). Managed Challenge interstitials ("Just a moment...") render the widget in shadow DOM — not supported here; use sister project mcp-stealth-chrome (Chrome+CDP) for those. Real-world bypass success also depends on IP reputation and browser fingerprint — code alone doesn't guarantee it.
🧪 bot.sannysoft.com → Firefox Fingerprint Pass
User Agent reports Firefox/135.0, WebDriver missing, WebDriver Advanced passed, Permissions prompt, Plugins length 5 passed, Languages en-US,en, WebGL Intel HD Graphics — all green. ("Chrome: missing" is expected — Camoufox spoofs Firefox, not Chrome.)
🔍 browserscan.net/bot-detection → All Categories Normal
WebDriver, User-Agent, CDP, Navigator — every detection category returns "Normal". Camoufox's C++-level Firefox patches leave zero automation signals.
Setup
One command for Claude Code:
claude mcp add camoufox -- npx -y mcp-camoufox@latestEvery other client takes the same server block — only the config file differs:
{
"mcpServers": {
"camoufox": {
"command": "npx",
"args": ["-y", "mcp-camoufox@latest"]
}
}
}| Client | Config file |
| --- | --- |
| Claude Code | claude mcp add camoufox --scope user -- npx -y mcp-camoufox@latest (drop --scope user for project-only) |
| Claude Desktop | macOS ~/Library/Application Support/Claude/claude_desktop_config.json · Windows %APPDATA%\Claude\claude_desktop_config.json · Linux ~/.config/Claude/claude_desktop_config.json |
| Cursor | ~/.cursor/mcp.json (global) or .cursor/mcp.json (project) |
| Windsurf | ~/.windsurf/mcp.json or .windsurf/mcp.json — uses "servers" instead of "mcpServers" |
| VS Code (Continue / Cline / Kilo) | ~/.continue/config.json or .vscode/mcp.json |
| Factory (Droid) | ~/.factory/mcp.json or .factory/mcp.json, with "type": "stdio" — or droid mcp add camoufox "npx -y mcp-camoufox@latest" |
| Antigravity | ~/.gemini/antigravity/mcp_config.json (global only) |
Two clients need a different shape:
// OpenCode — ~/.config/opencode/opencode.json ("local", not "stdio"; command is one array)
{ "mcp": { "camoufox": { "type": "local", "command": ["npx", "-y", "mcp-camoufox@latest"], "enabled": true } } }
// Trae — ~/.trae/mcp.json (mcpServers is an ARRAY)
{ "mcpServers": [ { "name": "camoufox", "command": ["npx", "-y", "mcp-camoufox@latest"] } ] }Requirements
Node.js 18+ is the only prerequisite (node --version). The Camoufox browser binary (~80 MB)
downloads itself on first launch — nothing else to install.
On Windows the same one-liner works; there is no standalone .exe because this is a Node package.
The browser lands in %LOCALAPPDATA%\camoufox, profile/screenshots/sessions in
%USERPROFILE%\.camoufox-mcp\, and output paths accept either C:\path\file.json or C:/path/file.json.
| Requirement | Version | Check |
| ----------- | ------- | ---------------- |
| Node.js | 18+ | node --version |
That's all. Camoufox browser binary (~80MB) downloads automatically on first launch.
All 133 Tools
Grouped by area. → Full reference, every tool and parameter
| Category | Tools | For example |
| -------- | ----- | ----------- |
| Browser Lifecycle | 4 | browser_launch, browser_close, reset_profile |
| Navigation | 4 | navigate, go_back, go_forward |
| DOM & Content | 7 | browser_snapshot, screenshot, get_text |
| Element Interaction | 12 | click, click_text, click_role |
| Keyboard | 2 | type_text, press_key |
| Mouse XY | 4 | mouse_click_xy, mouse_move, click_turnstile |
| Wait | 7 | wait_for, wait_for_navigation, wait_for_url |
| Tabs | 4 | tab_list, tab_new, tab_select |
| Cookies | 3 | cookie_list, cookie_set, cookie_delete |
| Local Storage | 3 | localstorage_get, localstorage_set, localstorage_clear |
| Session Storage | 3 | sessionstorage_get, sessionstorage_set, sessionstorage_clear |
| JavaScript | 2 | evaluate, inject_init_script |
| Element Inspection | 5 | inspect_element, get_attribute, query_selector_all |
| Frames | 2 | list_frames, frame_evaluate |
| Batch Operations | 6 | batch_actions, fill_form, login_classic |
| Viewport | 2 | get_viewport_size, set_viewport_size |
| Scroll | 2 | scroll, scroll_to |
| Dialog | 2 | dialog_handle, dialog_auto_handle |
| Accessibility | 1 | accessibility_snapshot |
| Console & Network | 9 | console_start, console_get, network_start |
| Compound (reduce round-trips) | 4 | wait_and_snapshot, back_and_snapshot, reload_and_snapshot |
| Smart Selectors (skip snapshot) | 3 | find_by_text, find_by_label, find_by_placeholder |
| Session Portability | 7 | cookie_export, cookie_import, cookie_export_file |
| Humanize / Anti-Bot | 5 | humanize_click, humanize_type, mouse_drift |
| Session Warmup & Detection | 2 | session_warmup, detect_anti_bot |
| Assertions | 4 | assert_element_visible, assert_text_present, assert_url_matches |
| Workflow Helpers | 3 | click_and_wait, wait_for_network_idle, describe_page |
| Scraping & Extraction | 4 | detect_content_pattern, extract_structured, extract_table |
| Browserless HTTP | 5 | http_request, http_session_cookies, scrape_markdown |
| Storage Inspection | 4 | storage_snapshot, storage_diff, indexeddb_list |
| Debug | 6 | server_status, get_page_errors, export_har |
| Site Automation | 2 | chatgpt_generate_image, chatgpt_generate_batch |
32 categories, 133 tools. The full table lives in docs/TOOLS.md so this page stays readable — nothing was dropped, and a script checks both against the running server's tool registry.
Examples
Read a page without launching anything. The browser costs seconds and ~400 MB; most fetches don't
need a DOM. smart_fetch only starts one if the response looks anti-bot blocked.
scrape_markdown(url="https://example.com/docs") # clean markdown, no browser
smart_fetch(url="https://shop.example.com/item/42") # escalates only if blocked
http_request(url="https://api.example.com/v1/me") # reuses the browser's cookiesLog in, then hit the API cheaply. Log in once with the browser, then stay browserless.
browser_launch(url="https://app.example.com/login")
smart_fill(fields_json='{"Email":"[email protected]","Password":"secret"}', submit_label="Sign in")
wait_for_change() # returns when the page really reacts
http_request(url="https://app.example.com/api/orders") # same session, no browser workFill a form without a snapshot. smart_fill matches by label; form_introspect tells you what a
form wants and why it is rejecting a submit.
form_introspect() # labels, types, required, validation state
smart_fill(fields_json='{"Customer name":"Rina","E-mail address":"[email protected]"}')Find out why a click did nothing — before spending the click.
assert_clickable(selector="#submit")
# FAIL: covered by div.overlay — that element would receive the clickRun a whole sequence in one call. Resumable: a failure tells you the index to restart from.
workflow_run(steps=[
{tool: "navigate", args: {url: "https://example.com"}},
{tool: "smart_fill", args: {fields_json: '{"Search":"camoufox"}'}},
{tool: "click_text", args: {text: "Search", within: "@dialog"}},
{tool: "wait_for_change", args: {}}
])Search through an engine you control (self-hosted SearXNG, or Brave/Tavily/Exa with a key).
search(query="firefox tls fingerprint", endpoint="http://127.0.0.1:8899")
scrape_markdown(url="<a url from the results>")How It Works
AI Agent (Claude, Cursor, Windsurf, VS Code)
|
| MCP Protocol (stdio JSON-RPC)
v
mcp-camoufox (Node.js)
|
| Playwright API (Juggler protocol, NOT CDP)
v
Camoufox (Patched Firefox binary)
|
| C++ anti-fingerprint patches
v
Website (Cloudflare, bot detection — bypassed)Why stealth works
- Juggler protocol instead of CDP — sites detecting Chrome DevTools Protocol cannot detect Camoufox
- C++ level patches — fingerprint spoofing at browser engine level, not JavaScript injection
- GeoIP auto-detection — timezone, locale, geolocation match your real IP
- Human-like behavior — optional
humanizemode for realistic mouse movements
Why sessions persist
Browser profile stored at ~/.camoufox-mcp/profile/. Cookies, localStorage, IndexedDB survive across sessions. Login once, stay logged in.
Why refs work better
browser_snapshot tags elements with data-mcp-ref attributes. This is:
- More token-efficient than sending full HTML
- More reliable than CSS selectors that break when sites update
- Clickable via
click(ref="e5")— no selector gymnastics
Data Storage
| Path | Contents |
| ------------------------------ | ---------------------------------------------- |
| ~/.camoufox-mcp/profile/ | Browser profile (cookies, localStorage, cache) |
| ~/.camoufox-mcp/screenshots/ | Screenshots, PDFs, HAR exports |
Reset everything: rm -rf ~/.camoufox-mcp/ — or call the reset_profile tool (browser must be closed first).
Switching between accounts on the same domain
The default profile persists across browser_close calls, so the next login on the same domain inherits cookies + session — sometimes redirecting to the wrong account. Two options:
**browser_launch(fresh_profile=true)**— uses a temp profile dir that's removed onbrowser_close. Best for one-off logins.**reset_profile**(browser must be closed) — wipes the shared profile entirely.
Troubleshooting
| Problem | Fix |
| --------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| "Browser not running" | Call browser_launch first |
| Click blocked by overlay | A synthetic pointer-event fallback fires and the response warns you (⚠). If the widget still ignores it, dismiss the blocker (press_key("Escape")) or use mouse_click_xy. |
| Clicked the wrong "Cancel"/"Save" | click_text now fails with a candidate list instead of guessing. Use within="@dialog" to stay inside the open modal, or index=N. |
| Click on a Radix/Headless UI/MUI option did nothing | The real click was blocked and the old fallback used a bare el.click(), which those libraries ignore. Fixed — the fallback now replays the full pointer sequence. Upgrade if you're on ≤0.7.2. |
| Login gone after browser_close | cookie_set without expires_days creates a session cookie, which no browser writes to disk. Pass expires_days=30, or use storage_state_save/auth_capture. browser_close now tells you how many cookies were dropped. |
| Stale refs after navigation | Call browser_snapshot again — refs regenerate each time |
| Window too large | browser_launch(width=1024, height=768) |
| navigate or tab_new times out after 30s, once in a while | Camoufox sporadically never commits a navigation (~1-2%). tab_new now detects it and retries on a fresh tab automatically; for navigate, call it again. This is upstream, not the 5th-tab bug that 0.9.11 fixed — that one broke every navigation after five tabs and is gone. |
| Widening the browser window leaves empty space instead of reflowing the page | Playwright pins a fixed viewport, and a fixed viewport never follows the OS window — dragging the frame bigger just adds blank area. Call set_viewport_size(w,h) after resizing, or launch with no_viewport=true to let the content track the window live. Since 0.10.3, browser_launch(width,height) also sizes the viewport to match, so a custom launch size no longer starts with a band of empty space. |
| Viewport smaller than the window (~80px) | That gap is browser chrome, not a bug. set_viewport_size(w,h) sets the exact viewport; browser_launch(no_viewport=true) lets the content fill the real window — but then the viewport can exceed the spoofed screen, which is an anti-bot tell (the launch reply warns when it happens). |
| First launch slow | Downloading Camoufox binary (~80MB). Happens once. |
| Huge snapshot output | Normal for big pages. Use get_text or evaluate instead. |
| iframe not accessible | Use list_frames + frame_evaluate |
| CAPTCHA appears | Cannot auto-solve. Use headless=false and solve manually. |
| Login lands on wrong account | Profile carry-over. Use fresh_profile=true on launch or reset_profile. |
| Need a PDF | save_pdf can't work on Firefox/Camoufox. Use screenshot(full_page=true). |
| browser_launch fails with Browser.setDefaultViewport ... isMobile | You're on mcp-camoufox <0.9.3, which let npm resolve playwright-core 1.62.x. Upgrade to 0.9.3+ — it pins playwright-core <1.61.0. |
| npm audit flags adm-zip in your project | It comes from camoufox-js, which pins adm-zip ^0.5.16. Our own overrides can't reach your tree (npm applies overrides only from the root project), so add "overrides": { "adm-zip": "0.6.0" } to YOUR package.json if your scanner requires it. |
| Field value looks concatenated | Fixed — fill/fill_form/batch_actions/login_classic now clear email/number inputs before typing. Upgrade if you're on ≤0.7.2. |
| humanize_click did nothing | Fixed — it now scrolls the element into view and errors if the element is outside the viewport. |
| navigate, tab_new or reload hangs ~30s and times out | Camoufox stops delivering the load/domcontentloaded events after the 5th page in a context, so every navigation waited out its full timeout on a page that had in fact loaded. Opening five tabs broke navigation for the rest of the session. Fixed in 0.9.11 — navigation now commits and polls document.readyState instead. Upgrade if you're on ≤0.9.10. |
| A tab opened after dialog_handle froze on a confirm() | The one-shot handler armed only the tabs that were open at the time, but told the persistent handler to stand down globally — so the dialog reached no handler, and a registered listener suppresses Playwright's auto-dismiss. Fixed in 0.9.11: tabs opened later are armed too. |
| MCP server silently dies | If you ran pkill -f camoufox, you killed the MCP node process too (its argv contains "camoufox"). Target the binary specifically — e.g. pkill -f "Camoufox.app/Contents/MacOS" — or use pkill -f camoufox-js. |
License
MIT
