AI Frontier Post
Project banner showing an AI assistant checking flight fares date by date in a stealth Firefox browser
An anti-detect Firefox at work: the pointer moves and keys are pressed while the agent checks fares date by date. Artwork: the invisible_playwright_mcp project banner (MIT license).

Your coding assistant can scaffold an entire app, then fall flat on the first real website: a captcha, a login wall, a bot check — and the agent is reading nothing. invisible_playwright_mcp (feder-cr/invisible_playwright_mcp) exists for exactly that gap: a Playwright MCP server whose browser is a Firefox patched at the C++ source, so the fingerprint is set inside the engine rather than bolted onto the page. It earned roughly 2,800 GitHub stars in its first two weeks and ships under the MIT license. This tutorial wires it into your assistant, wakes the browser, and sends it on a real errand.

What you’ll need

1. Install uv

The README’s own install lines. Windows, in PowerShell:

powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
$env:Path = "$env:USERPROFILE\.local\bin;$env:Path"

Linux:

curl -LsSf https://astral.sh/uv/install.sh | sh
source $HOME/.local/bin/env

2. Register the server in your client

Three clients install it as a plugin or extension. Claude Code:

claude plugin marketplace add feder-cr/invisible_playwright_mcp
claude plugin install invisible-playwright-mcp@feder-cr

Codex:

codex plugin marketplace add feder-cr/invisible_playwright_mcp
codex plugin add invisible-playwright-mcp@feder-cr

Gemini CLI:

gemini extensions install https://github.com/feder-cr/invisible_playwright_mcp

Clients that take a config file (Claude Desktop, Cursor, Windsurf, Cline) get a block under top-level mcpServers:

{
  "mcpServers": {
    "stealth": {
      "command": "uvx",
      "args": ["invisible-playwright-mcp"]
    }
  }
}

File locations, straight from the wiki: Claude Desktop macOS ~/Library/Application Support/Claude/claude_desktop_config.json, Windows %APPDATA%\Claude\claude_desktop_config.json; Cursor .cursor/mcp.json per project or ~/.cursor/mcp.json globally; Windsurf ~/.codeium/windsurf/mcp_config.json; Cline via its MCP panel. Zed calls the key context_servers, VS Code calls it servers with "type": "stdio", and Codex TOML takes [mcp_servers.stealth] with command and args.

Project walkthrough: ask your assistant in Claude Code, Codex, or Gemini CLI over MCP and it drives a stealth Firefox
One prompt, one browser, one identity: ask your assistant and the MCP server drives the page like a person. Artwork: invisible_playwright_mcp project banner (MIT license).

Now the wiki’s warning, which earns its bold type: “Added” is not “connected.” Every one of these writes a config entry without running anything — a typo, a missing uv, or the first-run engine download all surface later as a server that won’t start. Verify with claude plugin list, codex mcp list, gemini extensions list, or your client’s MCP panel before you trust it.

3. Wake the browser

The toolset mirrors Microsoft’s Playwright MCP, so prompts written for it carry over — with one deliberate departure: there are no tab tools. The roster: browser_open, browser_close, browser_list, browser_status, browser_navigate, browser_read_text, browser_snapshot, browser_read_html, browser_take_screenshot, browser_watch, browser_click, browser_click_at, browser_type, browser_select_option, browser_press_key, browser_upload_files, browser_evaluate.

browser_open is the first call of every session — nothing else opens a browser. With no arguments it brings back the person this session already was: same seed, same exit, same profile. A session is one identity, main; beside it sits exactly one helper, support, for things that must not touch that identity — a temporary mailbox for a verification code, a lookup, a page you don’t want tied to your logins. The two share nothing. And a browser drives one page; when you need a second page, support is the answer, by design, so cookies never leak between identities.

First start downloads the engine — the patched Firefox — from a GitHub release, and browser_open reports the progress until it’s there. The README’s privacy note is plain: that request carries no identifier, and nothing else leaves your machine except what you and your model provider already see.

4. Send it on a real errand

The project’s own worked example is fare-hunting — and it’s the right shape for any task: paste the URL, spell out the steps like you’re briefing a person, and forbid guessing:

Go to <paste the URL>. One way, Milan to Lisbon, economy, one checked bag,
one adult. Check every date from the 12th to the 16th of next month, one at a
time, and read the cheapest fare for each day. The date field is a calendar
widget, so click the days rather than typing them. If a date has no
availability, say so. Do not guess a number.

It drives the page the way a person would: the pointer moves, keys are pressed, each day is clicked in turn, and every fare is read off the page — not hallucinated. The README’s worked examples and transcripts live in the repo’s articles/ folder if you want more task shapes to copy.

5. Make it persistent (and give it a better exit)

These go under env on the server entry in your config file. On the command line, Codex takes --env KEY=value; the Claude Code plugin and Gemini CLI extension carry a fixed config block, so they read these from the environment the client starts in — export the variable, then start the client.

6. Or skip the assistant and use the web UI

The package ships its own interface — chat on the left, the live browser on the right:

export OPENROUTER_API_KEY=sk-or-...
uvx invisible-playwright-mcp ui

Then open http://127.0.0.1:8765. The default model is z-ai/glm-5.3-flash (overridable with --model or INVISIBLE_MCP_MODEL). The README’s own security advice: don’t pass the key as a flag — it lands in your shell history and, on Linux, in the process list. Prefer the environment variable or a .env file beside the command. And note that changing --host “exposes an interface that has no authentication.”

Project walkthrough: the standalone web UI with chat on the left and the live browser on the right
The standalone route: the package’s own web UI — chat on the left, the live browser on the right, an OpenRouter key doing the driving. Artwork: invisible_playwright_mcp project banner (MIT license).

What you built

Your assistant now drives a real, persistent browser identity — navigation, reading, clicking, typing, dropdowns, keys, screenshots, a live window view, and a JavaScript reader — over an MCP server called stealth in your config. One identity (main) that survives restarts, one scratch helper (support) that shares nothing with it, and a fingerprint set inside the engine rather than bolted onto the page.

Honest limitations

Verify the server is actually connected, send it one real errand before trusting it with ten, and keep the proxy in mind before you point it at anything that checks where you’re coming from.