{
  "markdown": "<!-- mcp-name: io.github.Evil-Bane/eyebrowse -->\n<div align=\"center\">\n\n# 👁️ EyeBrowse\n\n### A stealthy, LLM-drivable browser engine — one codebase, two faces.\n\nA **Python library** *and* an **MCP server** for driving a real, hard-to-detect browser, so\nlegitimate automation isn't false-flagged or IP-banned by Cloudflare, DataDome, Akamai, or\nPerimeterX. Built on **CloakBrowser** — a stealth **Chromium** (Chrome/146) that's a Playwright\ndrop-in — so EyeBrowse gets the full **Chrome DevTools Protocol**: trusted cursorless clicks,\ndeep network inspection, MHTML, PDF, and native video.\n\n[![CI](https://github.com/Evil-Bane/eyebrowse/actions/workflows/ci.yml/badge.svg)](https://github.com/Evil-Bane/eyebrowse/actions/workflows/ci.yml)\n[![PyPI](https://img.shields.io/pypi/v/eyebrowse?color=3775A9&logo=pypi&logoColor=white)](https://pypi.org/project/eyebrowse/)\n[![Python 3.12](https://img.shields.io/badge/python-3.12-3776AB?logo=python&logoColor=white)](https://www.python.org/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-22c55e.svg)](LICENSE)\n<br/>\n[![MCP tools](https://img.shields.io/badge/MCP-85_tools-7c3aed.svg)](docs/TOOLS.md)\n[![Engine: CloakBrowser](https://img.shields.io/badge/engine-CloakBrowser%20(stealth%20Chromium)-4285F4.svg)](https://pypi.org/project/cloakbrowser/)\n[![Code style: Ruff](https://img.shields.io/badge/lint-ruff-261230.svg?logo=ruff&logoColor=white)](https://github.com/astral-sh/ruff)\n[![PRs welcome](https://img.shields.io/badge/PRs-welcome-22c55e.svg)](CONTRIBUTING.md)\n\n![EyeBrowse — an AI agent driving a stealth browser past Cloudflare, over MCP](https://raw.githubusercontent.com/Evil-Bane/eyebrowse/master/docs/demo.gif)\n\n<sub>▶ Full-quality MP4: <a href=\"https://github.com/Evil-Bane/eyebrowse/blob/master/docs/demo.mp4\">docs/demo.mp4</a> — an AI agent drives EyeBrowse over MCP: clears a Cloudflare check, then reads real docs (asyncio · httpx · MDN).</sub>\n\n</div>\n\n---\n\n## Why EyeBrowse?\n\n- 🥷 **Stealth by default** — engine-level fingerprint spoofing (`geoip` + `humanize` on out of the box, novel fingerprint per launch); `navigator.webdriver` masked; viewport auto-sized to the spoofed screen. No `puppeteer-extra` band-aids — the anti-detection is *compiled into the browser*.\n- 🤖 **Built for LLMs** — pages are read as an **ARIA tree with `[ref=…]` handles**; the model acts by ref (`click`/`type`/`hover`), not by brittle CSS or raw pixels. Cross-origin iframes, shadow DOM, popups — handled.\n- ⚡ **Chrome DevTools Protocol** — **trusted, cursorless clicks** by node ref (`Input.dispatchMouseEvent`), raw `Network`/`Performance`/`Emulation` access, **MHTML** snapshots, **PDF** export, and **native video** — all reachable as tools.\n- 🧰 **Library *and* MCP from one codebase** — a clean Python API (`EyeBrowse` + `Session`), mirrored 1:1 by a thin **MCP server** (**85 `browser_*` tools**) for Claude Code and any MCP client.\n- 🪟 **Never boxed in** — the curated high-level API doesn't hide Playwright: reach `session.page` / `.context` / `.browser` for anything it doesn't wrap.\n- 🔋 **Batteries included** — multi-session, proxy + identity rotation, API-mode captcha solvers, native video, full **HAR** capture, and clean-markdown extraction.\n\n> **Scope.** EyeBrowse is a low-level browser *engine* — it holds **no workflow logic**.\n> Consumers decide *what* to do; the engine provides *what's possible*.\n\n## Contents\n\n[Quickstart](#quickstart) · [Install](#install) · [Features](#features) · [Compare](#how-eyebrowse-compares) · [Library](#use-as-a-library) · [MCP](#use-over-mcp) · [Proxy & identity](#proxy--identity-optional) · [Extraction](#extraction) · [Recording](#recording) · [How it works](#how-it-works) · [Caveats](#caveats) · [Tools](docs/TOOLS.md) · [License](#license)\n\n## Quickstart\n\n```bash\npip install eyebrowse\n# The stealth-Chromium binary downloads automatically on first launch — nothing else to run.\n```\n\n```python\nimport asyncio\nfrom eyebrowse import EyeBrowse\n\nasync def main():\n    eb = EyeBrowse()                          # stealth defaults: geoip · humanize\n    async with eb.session() as s:\n        await s.navigate(\"https://example.com\")\n        print(await s.snapshot())             # ARIA tree with [ref=...] handles\n        await s.click(\"e6\")                   # act on a ref from the snapshot\n    await eb.aclose()\n\nasyncio.run(main())\n```\n\n…or wire it into **Claude Code** (or any MCP client) — see [Use over MCP](#use-over-mcp).\n\n## Install\n\n**From PyPI**\n\n```bash\npip install eyebrowse                 # or: uv pip install eyebrowse\n# CloakBrowser fetches its Chromium binary lazily on first launch — nothing to run.\npip install \"eyebrowse[extract]\"     # optional: + Crawl4AI markdown extraction (heavier)\n```\n\n**From source (development)**\n\n```bash\ngit clone https://github.com/Evil-Bane/eyebrowse && cd eyebrowse\nuv sync                              # core engine  (add --extra extract for Crawl4AI)\ncp .env.example .env                 # only if you use a proxy / captcha keys\n```\n\nPython 3.12 (pinned `<3.13`). Engine: `cloakbrowser>=0.3` (stealth Chromium, Chrome/146), on\n`playwright 1.60` and `mcp 1.27`.\n\n## Features\n\n| | |\n|---|---|\n| 🥷 **Stealth** | CloakBrowser's patched-Chromium fingerprint spoofing (novel `--fingerprint` per launch); `geoip` + `humanize` by default; `webdriver` masked; viewport matched to the spoofed screen. |\n| 🤖 **LLM interaction** | `aria_snapshot(mode=\"ai\")` → ARIA tree + `[ref]` handles; click / type / hover / select / drag / file-upload / dialogs / keyboard; coordinate mouse too. |\n| ⚡ **CDP** | **trusted cursorless click** by ref, raw CDP (`Network` / `Performance` / `Emulation`), **MHTML** capture, **PDF** export. |\n| 🪟 **Frames & DOM** | cross-origin iframe routing by ref, shadow-DOM piercing, popup/new-tab switching, `evaluate` inside any frame. |\n| 🗂 **Multi-session** | independent stealth sessions, each with its own context / identity / proxy. |\n| 🌐 **Network** | inspect requests/responses (incl. XHR/fetch bodies & WebSocket frames), block URLs, mock responses, go offline, full **HAR** export. |\n| 💾 **State** | cookies, localStorage & sessionStorage (CRUD), `storage_state` save/reload. |\n| 🪪 **Identity rotation** | fresh fingerprint + isolated profile + paired proxy; pluggable residential `ProxyProvider`. |\n| 🧩 **Captcha** | pluggable **API-mode** solvers (CapSolver / 2Captcha / CapMonster / NextCaptcha) + TOTP — no browser extension. |\n| 📄 **Extraction** | Crawl4AI `raw:` feed → clean, token-efficient **markdown** (no LLM, no API keys). |\n| 🎥 **Capture** | screenshots, Playwright tracing, and **native video** (`.webm`). |\n| ✅ **Verify & debug** | assertions, element highlighting, locator generation, geolocation/header emulation. |\n\nFull per-tool reference: **[docs/TOOLS.md](docs/TOOLS.md)** (85 tools across 18 groups).\n\n## How EyeBrowse compares\n\n|                                                   |     EyeBrowse      | Playwright&nbsp;MCP |    browser-use     | playwright-stealth |\n| :------------------------------------------------ | :----------------: | :-----------------: | :----------------: | :----------------: |\n| Anti-detection **compiled into the browser**      |         ✅         |         ❌          |         ❌         |   ⚠️ JS patches    |\n| LLM-native ARIA **`[ref]`** interaction model     |         ✅         |         ✅          |         ✅         |         ❌         |\n| Ships an **MCP server**                            |   ✅ (85 tools)    |         ✅          |     ⚠️ partial     |         ❌         |\n| One codebase: Python **library *and* MCP**        |         ✅         |     MCP-only        |     lib-only       |     lib-only       |\n| Full **CDP** (trusted clicks · network · MHTML · PDF · video) | ✅     |     ⚠️ partial      |         ❌         |     ⚠️ partial     |\n| **Captcha** (API-mode) + TOTP                     |         ✅         |         ❌          |         ❌         |         ❌         |\n| **Proxy + identity rotation** built in            |         ✅         |         ❌          |     ⚠️ partial     |         ❌         |\n| Cross-origin iframes · shadow DOM · popups        |         ✅         |         ✅          |     ⚠️ partial     |        n/a         |\n\n<sub>Fair-use note: each project targets a different niche — this compares them on the axes EyeBrowse optimizes for (stealth + LLM-drivable + one library/MCP codebase), not as an overall ranking.</sub>\n\n## Use as a library\n\n```python\nimport asyncio\nfrom eyebrowse import EyeBrowse\n\nasync def main():\n    eb = EyeBrowse()                           # stealth defaults\n    try:\n        async with eb.session() as s:          # a stealth session (auto-closed)\n            await s.navigate(\"https://example.com\")\n            print(await s.snapshot())          # ARIA tree with [ref=...] handles\n            await s.click(\"e6\")                # act on a ref\n            await s.type(\"e8\", \"hello\", submit=True)\n            png = await s.screenshot(full_page=True)\n            title = await s.page.title()        # full Playwright power when you need it\n    finally:\n        await eb.aclose()\n\nasyncio.run(main())\n```\n\nRun the included proof: `uv run python examples/direct_usage.py`.\n\n## Use over MCP\n\nEyeBrowse ships an MCP server (`eyebrowse-mcp`, FastMCP over stdio). Add it to any MCP client.\n\n**Claude Code (CLI):**\n\n```bash\nclaude mcp add eyebrowse -- eyebrowse-mcp\n```\n\n**Any MCP client (JSON config):**\n\n```json\n{\n  \"mcpServers\": {\n    \"eyebrowse\": {\n      \"command\": \"eyebrowse-mcp\"\n    }\n  }\n}\n```\n\nThen drive the loop: `browser_navigate(url)` → read the snapshot → act by ref\n(`browser_click` / `browser_type` / …). A default session is auto-created, so most tools just\nwork. Full list: **[docs/TOOLS.md](docs/TOOLS.md)**.\n\n## Proxy & identity (optional)\n\nRuns **proxyless by default** (`geoip` still aligns locale/timezone to your real IP). Add a proxy\nonly when you want one:\n\n```python\nawait eb.new_session(proxy=\"http://user:pass@residential.example:8080\")\nawait eb.rotate_identity(proxy=\"socks5://host:1080\")   # fresh fingerprint + paired IP\nawait eb.new_session(no_proxy=True)                     # force proxyless\n```\n\nSet a default once via `EYEBROWSE_PROXY_*` in `.env`, `eb.set_static_proxy(...)`, or a custom\n`ProxyProvider` for rotation. Over MCP: `browser_new_session(proxy_url=…)` /\n`browser_new_identity(proxy_url=…)` / `browser_set_proxy(…)`.\n\n> **reCAPTCHA v3 / reputation gates** are score-based and key off IP + session reputation — a\n> fresh browser on a flagged IP fails regardless of stealth. Pair EyeBrowse with a clean\n> residential proxy.\n\n## Extraction\n\n`eb.extract()` (or `browser_extract`) hands the rendered HTML to Crawl4AI's `raw:` feed and\nreturns clean, pruned **markdown** — **no LLM is called and no LLM keys are ever read**; the\nconsuming agent does any structuring.\n\n```python\nmd  = await eb.extract()                            # markdown string\nres = await eb.extract(output_path=\"data/page.md\")  # → {\"path\": ..., \"chars\": ...}\n```\n\n## Recording\n\n**Native video** — Playwright records the whole session to a `.webm`, written on close. The path\nis known up-front; the file finalizes when the session closes:\n\n```python\ns = await eb.new_session(record_video=True)\n# ... drive the browser ...\nprint(await s.video_path())          # path is known up-front; file finalizes on close\nawait eb.close_session(s.id)\n```\n\nOver MCP: `browser_new_session(record_video=True)` → `browser_video_path`. Want a GIF for a README?\nConvert the `.webm` with ffmpeg (`ffmpeg -i demo.webm demo.gif`). The demo at the top was captured\nthis way — see **`examples/make_demo.py`**.\n\n## How it works\n\n```\nCONSUMERS                         ENGINE (library: eyebrowse/)\n Claude Code  ──MCP──▶  mcp/  ──▶  EyeBrowse façade (public API)\n your code   ─ import ──────────▶   ├─ BrowserEngine (CloakBrowser / stealth Chromium)\n any MCP client                     ├─ proxy / identity rotation (pluggable)\n                                    ├─ captcha solvers (pluggable, API-mode)\n                                    └─ Crawl4AI (raw: feed) → clean markdown\n```\n\nThe façade (`EyeBrowse` + `Session`) is the product; the MCP adapter is a thin 1:1 wrapper over\nit. The high-level API is curated and LLM-friendly — *not* a reimplementation of all of Playwright\n— and the raw `page` / `context` / `browser` objects are always one attribute away. The launcher\nis the only engine-specific layer; everything else is plain Playwright.\n\n## Caveats\n\nWorth knowing:\n\n- **`evaluate`** runs in the page's main world (page globals reachable). To override a page's\n  widget globals and fire a site callback (e.g. for captcha), EyeBrowse injects a `<script>` so the\n  code runs in the page world — see `captcha/inject.py`.\n- **HAR export closes the session** — Playwright only flushes the HAR buffer when the context\n  closes. Use the checkpoint pattern: `browser_storage_state` → `browser_har_export` →\n  `browser_new_session(storage_state=...)`. For the initiator-rich Chrome HAR (JS call stacks),\n  reach the `Network.*` domain via `browser_cdp_send`.\n- **Native video is `.webm`** — convert to GIF/MP4 with ffmpeg if you need another format.\n\n## Project layout\n\n```\neyebrowse/\n  api.py            EyeBrowse façade — the single public entry point\n  config.py         settings / secrets (pydantic-settings)\n  snapshot.py       aria_snapshot(mode=\"ai\") + aria-ref= resolution\n  proxy.py          ProxyConfig + pluggable ProxyProvider\n  identity.py       Identity + random_identity() (isolated profile dir)\n  extract.py        Crawl4AI raw: feed → markdown (lazy, optional dep)\n  engine/           engine.py (CloakBrowser launch) + session.py (verbs + registry)\n  captcha/          solver ABC + 4 providers + DOM detect/inject\n  mcp/              FastMCP server + state + tools/ (18 groups · 85 tools)\nexamples/direct_usage.py   library proof (no MCP)\nexamples/make_demo.py      the native-video demo above\ndocs/TOOLS.md              full tool reference\n```\n\nBuild notes, version-pin rationale, and verified engine behavior live in **[CLAUDE.md](CLAUDE.md)**.\n\n## Use responsibly\n\nEyeBrowse drives a real browser with anti-detection features. Use it only against sites you\nown or are explicitly authorized to automate, and within their terms and applicable law.\n\n## License\n\n[MIT](LICENSE) © Evil-Bane\n\n<div align=\"center\">\n<br/>\n\n**Found EyeBrowse useful?** ⭐ Star the repo — it genuinely helps.\n\n<sub>Built with Python · Playwright · CloakBrowser · FastMCP · the Model Context Protocol</sub>\n\n</div>\n",
  "bytes": 14514,
  "sha": "978ff36d00dad9aa1b37b8fd44ce6040ba95e4852644bb635ca2ead759d45343",
  "repo_slug": "evil-bane/eyebrowse",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_evil_bane_eyebrowse_8ca57223/readme"
}