MCP Camoufox
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": true
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| browser_launchA | Launch Camoufox stealth browser and navigate to URL. Browser persists between calls. By default cookies/localStorage persist in ~/.camoufox-mcp/profile. Set fresh_profile=true to start with a clean temp profile (auto-cleaned on browser_close) — useful when switching between accounts on the same domain. |
| browser_closeA | Close the browser. Cookies are preserved in the persistent profile (~/.camoufox-mcp/profile). If the launch used fresh_profile=true, the temp profile is removed. |
| reset_profileA | Delete the persistent profile (~/.camoufox-mcp/profile) entirely. Use to start fresh — cookies, localStorage, history all wiped. Browser must be closed first (call browser_close before this). |
| navigateC | Navigate to a URL. |
| go_backB | Navigate back in history. |
| go_forwardB | Navigate forward in history. |
| reloadB | Reload the current page. |
| browser_snapshotA | Get visible interactive elements with ref IDs. Use refs with click/fill. Always call after navigation. On large pages (Outlook, dashboards) the response can be truncated — narrow with roles=["button","textbox"] or paginate with offset/limit. Refs stay stable regardless of filters (every visible element is still numbered). |
| screenshotA | Screenshot the page, or a single element with ref/selector (great for documenting one modal). Returns the IMAGE inline — no second Read call — plus the saved path. Set return_image=false for path only. |
| clickA | Click element by ref ID from browser_snapshot. Auto JS-fallback for overlays. |
| click_textA | Click element by visible text. If the text matches several elements it FAILS with a numbered candidate list instead of silently clicking the first one — narrow with within ("@dialog", a CSS selector, or "ref:e5") or pick one with index. |
| click_roleA | Click element by ARIA role and name. Same ambiguity guard as click_text: several matches → candidate list, not a guess. |
| hoverB | Hover over element by ref ID. |
| fillA | Fill input/textarea by ref ID. Always replaces existing content (email/number inputs are cleared explicitly first — Firefox's select-all is a no-op on those, which would otherwise append). |
| select_optionC | Select option from dropdown. |
| checkC | Check checkbox or radio button. |
| uncheckC | Uncheck a checkbox. |
| type_textA | Type text char by char via keyboard. |
| press_keyB | Press key or combo (Enter, Escape, Control+a, etc.). |
| wait_forB | Wait for element/text to appear or disappear. |
| wait_for_navigationC | Wait for page load to complete. |
| wait_for_any_ofA | Race multiple wait conditions — returns the first that matches, so the agent can branch immediately without sequential probes. Each condition is {kind: 'selector'|'text'|'url_contains'|'title_contains', value: string}. Returns the index + kind + value of the winning condition (or 'timeout' if none matched). Ideal for post-login flows where the next page could be any of several (e.g. 'Stay signed in?', 'Skip for now', or the inbox directly). |
| evaluateC | Execute JavaScript in page context. |
| get_urlA | Get current URL and title. |
| get_textC | Get visible text from page or element. |
| get_htmlC | Get HTML content from page or element. |
| tab_listA | List all open tabs. |
| tab_newB | Open new tab. |
| tab_selectA | Switch to a tab by index, or by url_contains (first tab whose URL contains the substring). |
| tab_closeA | Close a tab by index (-1 = active), or by url_contains. |
| cookie_listC | List cookies. |
| cookie_setA | Set a cookie. IMPORTANT: with expires_days=0 this creates a SESSION cookie, which Firefox keeps in memory only — it is gone after browser_close even though the profile itself persists. Pass expires_days (e.g. 30) to write a login session that survives a relaunch. |
| cookie_deleteC | Delete cookies. Both empty = clear all. |
| dialog_handleA | Set handler for the next alert/confirm/prompt on ANY open tab (first dialog wins, handler then clears). |
| upload_fileC | Upload file to file input. |
| chatgpt_generate_imageA | Generate or edit an image on chatgpt.com end-to-end and save it to disk in ONE call. Opens a fresh chat, optionally uploads reference images (e.g. a brand logo), submits the prompt, waits for the generated image to finish, then writes the result PNG to output_path. Requires an authenticated chatgpt.com session (import cookies first via cookie_import). Returns the saved path and pixel dimensions. Note: chatgpt image generation is slow (~60-120s) — set timeout_ms accordingly. |
| chatgpt_generate_batchA | Generate MANY images on chatgpt.com IN PARALLEL (one tab per job, fire-all-then-collect) and save each to disk. Submits every job first WITHOUT waiting, then waits for all generations concurrently — far faster than sequential. For a CONSISTENT feed set, pass shared_image_paths (e.g. [logo] and/or a style-reference image like a previously-generated hero) uploaded to EVERY tab, plus style_suffix (a shared style spec) appended to every prompt. Requires an authenticated chatgpt.com session (import cookies first). Returns per-job results (saved path / ok / bytes / error). |
| scrollC | Scroll the page. |
| console_startA | Start capturing console messages from all tabs. |
| console_getB | Get captured console messages. |
| network_startA | Start capturing network requests. With capture_bodies=true also records request/response headers + text bodies (json/text/xml/form only, capped at body_limit bytes) so you can inspect API payloads via network_get_detail — no need to pivot to evaluate()+fetch(). |
| network_getA | List captured network requests in capture order, keeping the most recent |
| network_get_detailA | Full request + response detail (headers and text body) for one captured request. Requires network_start(capture_bodies=true) BEFORE the request fired. Identify the request by id (from network_get) or by url substring. |
| save_pdfA | Save page as PDF. NOTE: Playwright can only generate PDFs in headless Chromium — Camoufox is Firefox, so this fails by design here. Use screenshot(full_page=true) instead. Kept for API compatibility. |
| batch_actionsC | Execute multiple actions in one call. Each action: {type, ref?, value?, text?, key?, url?}. |
| fill_formC | Fill multiple form fields and optionally submit. |
| login_classicA | Composite login for classic email→password forms (Google, Microsoft, generic SSO). Auto-detects the email field, clicks Next/Continue on multi-step forms, fills the password, submits, and optionally enters a TOTP 2FA code. Collapses the usual 5–8 fill/click/snapshot calls into one. Heuristic — if a form is unusual, fall back to individual fill/click tools. Returns the step log + a fresh snapshot. |
| navigate_and_snapshotB | Navigate to URL then return snapshot — combined in one call. |
| intercept_startA | Block requests before they leave the browser. Blocking image/media/font/stylesheet typically removes most of a page's bytes — the single biggest speed-up for scraping — and block_urls kills trackers and ad frames. Routed on the context, so tabs opened later are covered too. Re-calling replaces the previous rules; intercept_stop removes them. 'document' cannot be blocked: it would abort the navigation itself. |
| intercept_stopA | Remove interception rules and report what they blocked. |
| intercept_logC | Show what interception blocked and allowed. |
| export_curlA | Rebuild a captured request as a runnable curl command, so you can replay or share an API call without re-deriving its headers. Needs network_start(capture_bodies=true) — headers are not recorded otherwise. |
| inspect_elementB | Get detailed info about an element (tag, attributes, bounding box, styles). |
| get_attributeB | Get a specific attribute value from an element. |
| query_selector_allB | Query elements by CSS selector, return text/attributes of all matches. |
| get_linksA | Get all links on the page with URL and text. |
| localstorage_getB | Get all localStorage data or a specific key. |
| localstorage_setC | Set a localStorage item. |
| localstorage_clearA | Clear all localStorage. |
| sessionstorage_getB | Get all sessionStorage data or a specific key. |
| sessionstorage_setC | Set a sessionStorage item. |
| mouse_click_xyA | Click at exact x,y coordinates. steps>0 adds interpolated pre-movement (human-like). |
| mouse_moveB | Move mouse to x,y. steps>0 interpolates path (human-like). |
| click_turnstileA | Auto-solve Cloudflare Interactive Turnstile checkbox. Locates the widget via in-page selectors AND the Playwright frame API (handles closed shadow roots that document.querySelector misses), polls for render, skips if already solved, then does a humanized real-mouse click with retries + small nudge, verifying the cf-turnstile-response token after each attempt. Managed Challenge full-page interstitials still need mcp-stealth-chrome. |
| drag_and_dropB | Drag from one element to another. |
| list_framesB | List all frames/iframes in the page. |
| frame_evaluateB | Execute JavaScript inside a specific frame/iframe. |
| wait_for_urlC | Wait for URL to match a pattern. |
| wait_for_responseB | Wait for a network response matching a URL pattern. |
| get_viewport_sizeA | Get current viewport dimensions. |
| set_viewport_sizeA | Set the viewport width and height. This is the exact control over what the page renders and what a screenshot captures. It does NOT resize the OS window: Camoufox reports a frozen outerWidth/outerHeight, so asking for a viewport larger than the launch window makes the content bigger than its own window — impossible geometry that a detector can read. The reply says so when that happens. |
| accessibility_snapshotA | Get accessibility tree snapshot — compact view of page structure for LLM understanding. |
| server_statusB | Health check — verify server, browser status, active tabs. |
| get_page_errorsA | Get uncaught JavaScript errors + unhandled promise rejections from the current page. Captured by a hook installed at browser_launch, so the buffer resets on every navigation (read it before navigating away). Max 100 entries per page load. |
| inject_init_scriptA | Inject a script that runs before every page load. |
| export_harA | Export captured network traffic as a HAR 1.2 file (openable in DevTools/other HAR viewers). Requires network_start first; headers and bodies are only included when network_start(capture_bodies=true) was used. |
| fingerprint_auditA | Report the fingerprint a site actually sees from this browser, and flag internal contradictions — the mismatches that get an automated browser detected are far more revealing than any single value. Read-only: it inspects, it does not change anything. |
| detect_content_patternA | Auto-detect repeated content patterns (cards, listings, rows) and suggest CSS selectors. Run this BEFORE extract_structured to find the right selectors. |
| extract_structuredA | Extract structured data from repeated elements (cards, rows, listings). Auto-deduplicates, filters empty items, extracts direct text only. Use detect_content_pattern first to find correct selectors. |
| extract_tableC | Extract data from an HTML table as JSON array. |
| scrape_pageB | Smart page scraper — auto-detect and extract main content, links, metadata. Strips nav/footer noise. |
| wait_and_snapshotA | Wait for selector/text then return snapshot. Combines wait_for + browser_snapshot in one call. |
| back_and_snapshotB | Navigate back + return snapshot. |
| reload_and_snapshotB | Reload page + return snapshot. |
| click_and_snapshotA | Click element by ref + wait + return snapshot. Perfect for buttons that trigger navigation/dialog. |
| find_by_textA | Find elements by visible text — returns EVERY match (total + a ref and ancestor path per candidate), so you can tell whether the one you want is really the one you'd click. Skip browser_snapshot when you know the text. |
| find_by_labelA | Find input element by its label text (). Returns ref + how many matched. |
| find_by_placeholderB | Find input by placeholder text. Returns ref + how many matched. |
| cookie_exportA | Export all cookies as JSON string. Use with cookie_import to transfer session. |
| cookie_importA | Import cookies from JSON (from cookie_export). Restores session state. |
| page_statsA | Page statistics: element count, size, load metrics. Use to decide extraction strategy. |
| storage_state_saveA | Save cookies + localStorage to a JSON file. Reload via storage_state_load on a fresh browser to skip login/CF entirely. |
| storage_state_loadA | Load cookies + localStorage from a JSON file (created by storage_state_save). Bypass CF/login if session is fresh. |
| auth_captureA | Save current session as named auth state (e.g. logged-in user). Convenience wrapper: storage_state_save to ~/.camoufox-mcp/sessions/.json |
| cookie_export_fileA | Export all cookies to a JSON file (Playwright format). |
| cookie_import_fileB | Import cookies from a JSON file (Playwright format). |
| humanize_clickA | Click element with humanized mouse approach (3-step Bezier-like curve before click). Use for anti-bot pages. |
| humanize_typeB | Type text with Gaussian-distributed delays between keystrokes (mean ~80ms, sigma ~30ms). Mimics human typing rhythm. |
| mouse_driftA | Random mouse movements over a duration — builds up mouse history before action (CF/DataDome behavior analysis). |
| mouse_recordA | Start recording mouse positions in the page (replay with mouse_replay). Re-calling replaces any previous recorder instead of leaking its listener. |
| mouse_replayA | Replay last recorded mouse path with original timing. |
| session_warmupA | Visit innocuous public sites (Google, Wikipedia) to build browsing history before targeting protected site. Helps with CF/DataDome IP scoring. |
| detect_anti_botA | Heuristic detection of anti-bot vendor on current page (Cloudflare, DataDome, Akamai, PerimeterX, Imperva). |
| assert_element_visibleA | Assert element exists and is visible. Returns success/fail (no throw). |
| assert_text_presentA | Assert text is present anywhere on page (case-sensitive substring). |
| assert_url_matchesC | Assert current URL matches pattern (substring or regex). |
| click_and_waitA | Click element then wait for navigation or selector. Atomic — fewer roundtrips than separate click + wait_for. |
| wait_for_network_idleA | Wait until there are no in-flight requests for idle_ms continuously. Requests are counted from the moment the page was opened, so one that was ALREADY in flight when you call this is not mistaken for idle. |
| describe_pageA | Compact LLM-friendly page summary (title, heading, key buttons, forms). Cheaper than browser_snapshot for agent context. Also returns |
| http_requestA | HTTP request WITHOUT a browser, using a real Firefox TLS/HTTP2 fingerprint (impit). By default it reuses the live browser's cookies for that URL, so you can log in with the browser and then hit the site's API cheaply. Far faster and lighter than navigating — use it for APIs, JSON, and any page that doesn't need JS. |
| http_session_cookiesA | Show which browser cookies would be sent with an HTTP request to this URL. Use it to confirm session sharing before relying on http_request. |
| searchA | Search the web through a search API YOU control — a self-hosted SearXNG, or Brave/Tavily/Exa with a key — and get back a normalised title/url/snippet list. This never scrapes a SERP: that shipped in 0.9.0 and was removed in 0.9.2 because engines answer some queries with confidently wrong results. A real API contract does not have that failure mode. Set MCP_SEARCH_ENDPOINT (and MCP_SEARCH_API_KEY when the provider needs one) to avoid passing them every call. |
| scrape_markdownA | Fetch a URL and return clean, LLM-ready markdown (headings, links, lists preserved; nav/footer/scripts stripped). Default path is browserless (impit) — fast and cheap. Set use_browser=true for JS-rendered pages (needs browser_launch). |
| smart_fetchB | Dual-mode fetch: tries the browserless HTTP path first and escalates to the stealth browser ONLY when the response looks anti-bot blocked. This is the efficiency core — high-volume reading stays cheap, the browser fires only when it's actually needed. |
| search_pageB | Grep the CURRENT page's visible text and return matches with surrounding context. Costs nothing compared to a snapshot or a screenshot — use it first to find where a term actually appears. |
| wait_for_changeA | Wait until the page actually CHANGES and report what changed (url / title / DOM size / text). This is the honest version of a fixed sleep after a click: it returns as soon as something happened, or tells you nothing did. |
| assert_clickableA | Hit-test an element WITHOUT clicking: would a real click actually land on it? Answers "why did my click do nothing?" before you spend the click. Reports the element that would intercept the click when something covers it. |
| scroll_toA | Scroll a specific element into view (the page-level |
| click_element_offsetB | Click at a percentage position inside an element instead of its centre — for wide labels whose real checkbox sits at the left edge, sliders, or split buttons. |
| click_at_cornerA | Click a corner of an element — close/X buttons, delete icons and dismiss controls usually live there, not in the centre. |
| paste_textA | Fill a field with a REAL paste. Puts the text on the clipboard and presses Ctrl/Cmd+V so the page receives a trusted paste event with actual clipboardData — the only thing that works for frameworks that listen to paste alone (Svelte 5 / SolidJS runes, some Qwik forms). Falls back to a synthetic event and then the native value setter. |
| form_introspectA | Analyse a form in one call: per field the label, type, current value, required/pattern/length constraints, validation state, and the JS framework it is bound to. Tells you what to fill and why a submit is being rejected without guessing from a snapshot. |
| smart_fillA | Fill form fields by their LABEL text (fuzzy, case-insensitive) instead of refs — no snapshot needed. Values go through the same clearing logic as fill, so email/number fields replace rather than append. |
| dialog_auto_handleA | Install a PERSISTENT dialog handler that stays armed across every dialog and every tab (dialog_handle is one-shot). Reads its action at fire time, so you can change it without re-arming. Set enabled=false to remove it. |
| sessionstorage_clearA | Clear all sessionStorage for the current origin (parity with localstorage_clear). |
| wait_for_requestA | Block until the page ISSUES a request matching a URL substring (wait_for_response waits for the reply). Use it to confirm an action actually fired its API call. |
| storage_snapshotA | Capture cookies + localStorage + sessionStorage + URL into a named slot, so storage_diff can tell you exactly what an action changed. |
| storage_diffA | Compare current storage against an earlier storage_snapshot — shows exactly which cookies/localStorage/sessionStorage keys were added, removed or changed. The fastest way to find which key holds a session token. |
| indexeddb_listA | List IndexedDB databases for the current origin. Many SPAs keep auth state and drafts here, invisible to cookie/localStorage tools. |
| indexeddb_deleteA | Delete an IndexedDB database by name for the current origin (clears SPA state that survives a cookie wipe). |
| performance_timelineA | Navigation + paint + resource timing for the current page: TTFB, DOMContentLoaded, load, FCP, LCP, and the 5 slowest resources. Note: Firefox does not implement layout-shift, so CLS is unavailable here. |
| browser_recoverA | Escape hatch when the browser is wedged and browser_close can't complete: force-drops the connection and resets server state so browser_launch works again. Also reports a profile lock held by another Camoufox process, which is the usual cause of 'A copy of Camoufox is already open'. |
| workflow_runA | Run a list of tool calls in sequence — any tool this server exposes, by name — and return a per-step log. Resumable: a failed run tells you the index, and start_at skips the steps that already succeeded. Each step is {"tool":"navigate","args":{"url":"…"},"label":"optional"}. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 133 tools
There are many near-synonymous tools for core actions: at least nine click variants, seven wait variants, and multiple snapshot/scrape/extract tools. The descriptions are detailed, but an agent still faces frequent ambiguity about which variant fits a given situation.
All names are snake_case and readable, but the verb/noun pattern is inconsistent: browser_launch and tab_new are noun_verb, get_url and cookie_list are verb_noun, and many tools are bare verbs like navigate, reload, hover, and scroll. There is no single predictable convention, though the mixed style is still navigable.
133 tools is an extreme count for any server, even a broad browser-automation toolkit. The surface area is bloated with specialized variants that could plausibly be consolidated, making the set hard to scan and reason about.
The domain is thoroughly covered: browser lifecycle, navigation, interaction, extraction, network capture, storage, cookies, dialogs, frames, anti-bot evasion, session management, and compound workflows all have dedicated tools. There are no obvious dead ends or major missing operations.