browser-for-ai

browser-for-ai

A CDP-native MCP server that lets AI agents drive a real Chrome browser with deep network/console inspection, robust page interaction, and the ability to reverse-engineer a site's API flow into runnable code with dependency chaining and replay verification.

Category
访问服务器

README

browser-for-ai (bfa)

License: MIT Node MCP TypeScript Tools

English · ภาษาไทย

A CDP-native MCP server that lets an AI agent (Claude Code and any other MCP client) drive a real Chrome at full depth — reading the network and console the way a human does with DevTools open, operating the page robustly, and reverse-engineering a site's API flow into runnable code.


Why bfa

The things a screenshot-only browser tool can't do:

  • ⭐ Turn a real session into runnable code. Mark a flow, perform it in the browser, and bfa synthesizes replay code (curl / TypeScript / Go / Python) with cross-call dependencies chained automatically — an auth token from one response becomes a variable the next request re-uses, not a baked-in literal. flow_replay then runs it for real to prove the reversal reproduces.
  • 🔬 See the whole network. Full request/response bodies (text and binary base64), the complete on-the-wire headers (Cookie and custom signing headers included, merged from CDP ExtraInfo), timing, redirect hops, and WebSocket frames — surfaced by the exact question you're asking: failures, pending (hangs), slow.
  • 🎮 Drive anything. Ref / CSS interaction and raw coordinate + touch for <canvas> / WebGL surfaces with no DOM. Every action reports the network / console / URL delta it caused.
  • 🧪 Shape traffic. Block / mock / modify requests, and throttle to Slow 3G / offline / custom bandwidth with CPU slowdown.
  • 🗂️ Real sessions. Many concurrent sessions, incognito, attach to your logged-in Chrome, save/restore cookies + storage, and complete cache clearing.

How it compares

Capability bfa typical browser MCPs
Reverse a captured flow → runnable code, dependency-chained + replay-verified ✅ ✗ (at most Playwright-script codegen from UI actions)
Full response bodies (text + binary) & WebSocket frames, on by default ✅ mostly metadata only
Secret redaction in the emitted code ✅ ✗
Coordinate + touch interaction for canvas / WebGL ✅ some (vision mode)
Attach to your logged-in Chrome ✅ ✅ (common)
Network / CPU throttling presets ✅ some
Cloud-scaled browsers · stealth · proxies · CAPTCHA ✗ (local by design) some cloud tools

bfa is a local, developer-facing inspection & reverse-engineering tool, not a cloud scraping farm — that focus is why the first three rows are rare elsewhere.


Requirements

  • Node.js ≥ 20
  • Google Chrome installed (or set BFA_CHROME_PATH to your Chrome binary)

Install & build

git clone https://github.com/icueth/browser-for-ai.git
cd browser-for-ai
npm install
npm run build      # → dist/server.js

Register with Claude Code

claude mcp add browser-for-ai --scope user -- node /absolute/path/to/browser-for-ai/dist/server.js

If node comes from a version manager (nvm, asdf, …), pass the absolute path to the node binary — the MCP server is spawned by a non-interactive shell that won't resolve aliases.

Verify with claude mcp get browser-for-ai (should say ✔ Connected). Tools load into a new session, so start a fresh Claude Code session afterward.


Quick start

browser_launch { "mode": "fresh", "url": "https://example.com" }   // real window
page_screenshot
net_list            // recent requests
net_failures        // anything that errored
net_pending         // anything still hanging
page_snapshot       // ref-annotated DOM
page_click { "selector": "#login" }
net_get { "url": "/api/login" }   // one call in full: headers + bodies
browser_close { "all": true }

Sessions

browser_launch { mode, url?, port?, profile?, incognito?, headless?, viewport? }

  • fresh — launch our own Chrome (headful by default; headless: true for none).
  • attach — connect to a Chrome started with --remote-debugging-port (only port is used; default 9222).
  • incognito: true — isolated context, no prior state.
  • Profiles. No profile → ephemeral temp profile wiped on close. A named { "profile": "work" } persists under ~/.bfa/profiles/work so logins survive. Two concurrent sessions on the same named profile collide; unnamed ones are always safe.
  • Viewport at launch, or page_set_viewport on a live session.

Manage with browser_sessions, browser_use { sessionId }, browser_tabs, browser_close. Most tools accept an optional sessionId; without it they target the active session.


Tool reference (44)

Sessions & lifecycle

tool purpose
browser_launch launch fresh / attach a session
browser_sessions list open sessions
browser_use set the default session
browser_tabs list a session's tabs/targets
browser_close close one session, or all
browser_clear_cache clear cache + cookies + storage
browser_hard_reload bypass-cache reload

Navigation, state & read

tool purpose
page_goto navigate to a URL
page_state url, title, readyState, viewport
page_set_viewport resize a live session's viewport
page_snapshot compact, ref-annotated DOM (source of element refs)
page_observe delta since last observe — new console/network/URL/DOM
page_screenshot PNG of viewport, full page, or one element
page_eval evaluate JS in the page, return the value

Interaction

tool purpose
page_click click a ref / selector (reports the delta)
page_type type into a field (clear:true to replace)
page_fill fill several fields in one call
page_select choose an <option> by value
page_key press a key or combo (e.g. "Enter", "Control+A")
page_hover hover an element
page_scroll scroll the window, or an element into view
page_upload attach file(s) to a file <input>
page_click_at click at raw {x, y} (canvas/WebGL)
page_tap_at touch-tap at {x, y}
page_drag drag between two points/elements

Network (deep read)

tool purpose
net_list recent requests (filter by url/method/type/status)
net_get one request in full: headers, request & response bodies
net_failures 4xx/5xx + transport failures with error detail
net_pending requests still in flight (hang candidates)
net_slow finished requests slower than a threshold
net_ws WebSocket connections + recent frames
net_wait wait until a matching request appears / settles

Traffic shaping & emulation

tool purpose
net_intercept_add block / mock / modify matching requests (CDP Fetch)
net_intercept_list list active intercept rules
net_intercept_clear remove intercept rules
net_throttle emulate network (offline / 3G / 4G / custom) + CPU slowdown

Console

tool purpose
console_list console messages (filterable by regex)
console_errors errors + uncaught exceptions with stacks

API-flow extraction

tool purpose
flow_mark mark the start of a flow in the recording
flow_export export captured calls as JSON summary or HAR
flow_synthesize generate replay code (curl/ts/go/python) with deps chained
flow_replay execute the reversed flow for real (Node fetch) to verify

Session persistence

tool purpose
session_save save cookies + local/session storage to ~/.bfa/state
session_restore re-apply a saved session (origin-scoped)

Reverse-engineering an API flow → runnable code

The flagship workflow. A page logs in with POST /api/login (returns a token), then calls GET /api/me with Authorization: Bearer <token>:

browser_launch { "mode": "fresh", "url": "https://app.example.com/login" }
flow_mark { "label": "login flow" }
page_fill { "fields": [
  { "selector": "#user", "value": "alice" },
  { "selector": "#pass", "value": "s3cret" }
]}
page_click { "selector": "#submit" }
flow_synthesize { "target": "curl" }

produces:

resp0=$(curl -s -X POST 'https://app.example.com/api/login' \
  -H 'content-type: application/json' \
  -d '{"user":"alice","pass":"s3cret"}')
token=$(echo "$resp0" | jq -r '.token')      # ← lifted from the response

curl -s -X GET 'https://app.example.com/api/me' \
  -H "authorization: Bearer $token"          # ← re-used, not a literal

flow_synthesize also emits TypeScript / Go / Python, flow_replay runs the sequence for real (deps resolved from each live response) and reports ✓ / ✗ per call, and { "redact": true } swaps secret-bearing header values and whole-token bodies for env placeholders.

Dependency detection is heuristic (exact / url-encoded / base64 / JWT-claim / substring). Unmatched values stay literal for you to review; always read the generated code before shipping it.


Cookbook

A. Debug a slow or hung page

browser_launch { "mode": "fresh", "url": "https://myapp.com" }
net_pending                      // the request that never finishes → the hang
net_slow { "thresholdMs": 1000 } // finished-but-slow calls, slowest first
net_failures                     // 4xx/5xx + transport errors
console_errors                   // the thrown stack trace
net_get { "url": "/api/user" }   // the failing call in full

B. Reverse-engineer an API into runnable code

browser_launch { "mode": "fresh", "url": "https://app.com/login" }
flow_mark { "label": "login+fetch" }
page_fill { "fields": [
  { "selector": "#user", "value": "me" },
  { "selector": "#pass", "value": "pw" }
]}
page_click { "selector": "#submit" }
flow_synthesize { "target": "python" }      // code with the token chained in
flow_replay                                  // ✓/✗ per call — verified

C. Stay logged in across runs

session_save { "name": "myapp" }             // first run, after logging in
// later:
browser_launch { "mode": "fresh" }
session_restore { "name": "myapp" }          // back in, no re-login

D. Drive a canvas / WebGL app

browser_launch { "mode": "fresh", "incognito": true, "url": "https://game.example",
                 "viewport": { "width": 390, "height": 844 } }  // portrait
page_click_at { "x": 195, "y": 700 }         // press a button drawn on the canvas
net_ws                                        // read the app's WebSocket frames
net_pending                                   // catch asset-load hangs

E. Test under a bad network / mocked endpoint

net_throttle { "preset": "slow-3g", "cpuRate": 4 }   // degrade the connection + CPU
net_intercept_add { "urlIncludes": "/api/config", "action": "mock",
                    "status": 200, "body": "{\"feature_x\":true}" }
browser_hard_reload
net_slow                                              // see what drags under 3G
net_throttle { "preset": "none" }                    // reset to full speed

F. Upload a file through a form

page_snapshot
page_upload { "selector": "input[type=file]", "files": ["/abs/path/resume.pdf"] }
page_click { "selector": "#submit" }
net_get { "url": "/upload" }                  // confirm the multipart request

Canvas / WebGL games

Puppeteer defaults to an 800×600 landscape viewport. A portrait game then renders letterboxed, and its full-screen input overlay can swallow coordinate clicks. Launch (or resize) with a portrait viewport so the canvas fills the screen:

browser_launch { "mode": "fresh", "incognito": true, "url": "…",
                 "viewport": { "width": 390, "height": 844 } }
page_set_viewport { "width": 390, "height": 844 }   // on a live session

Keep hasTouch:false (default) so page_click_at (a real mouse click) drives games listening for mouse input. For touch-only games, set the viewport hasTouch:true and use page_tap_at { x, y }.


Which mode do I want?

  • fresh (default) — a throwaway Chrome, zero setup. Use for reverse-engineering a public flow or any site that does not need your existing login.
  • attach — connect to a Chrome you started with a debug port. Use when you need real logins/cookies or a human-looking browser: navigator.webdriver is false, real profile & fingerprint, so it passes basic bot checks that a puppeteer-launched Chrome fails. Setup below.

Attach to a real, logged-in Chrome

A normally-opened Chrome has no debug port, and Chrome 136+ refuses one on the default profile (an anti-cookie-theft hardening) — so attach always uses a separate profile:

# dedicated profile (recommended) — a window opens; log in there once, it persists
./bin/bfa-chrome 9222

# …or reuse your existing logins via a COPY of your profile (a non-default dir)
cp -R "$HOME/Library/Application Support/Google/Chrome" "$HOME/.bfa/real-copy"
./bin/bfa-chrome 9222 "$HOME/.bfa/real-copy"

Then: browser_launch { "mode": "attach", "port": 9222 }. (If the port isn't up, the tool's error tells you this exact recipe.)

⚠️ A copied real profile hands the agent every logged-in session it contains — email, cloud consoles, banking, source control. It can read those pages and act as you. Prefer the dedicated profile; use a real-profile copy only when you need those logins and accept that blast radius.

Do not point bfa-chrome at your live default profile: on Chrome 136+ the debug port silently won't open, and it would also collide with your running Chrome (one process per profile dir).


Roadmap

Gaps we know about, in rough priority order:

  • iframe-aware refs — page_snapshot / interaction currently resolve the top document only; cross-frame ref support is the next correctness item.
  • Device emulation presets — bundle UA + viewport + touch + geolocation + permission grants into one call.
  • PDF export — Page.printToPDF for report/invoice-style pages.
  • Playwright/Puppeteer test emission — a new flow_synthesize target that outputs a runnable test script, not just replay code.
  • Natural-language element targeting — an optional LLM-assisted layer over the existing deterministic ref model.
  • Performance tracing — a thin Tracing.start/stop wrapper.

Out of scope by design: cloud-scaled browsers, stealth/anti-bot, and residential proxies — bfa stays a local inspection tool.


Notes & limitations

  • The agent sees whatever the attached/launched browser sees. Treat an attached real-profile Chrome as full access to your logged-in accounts.
  • Native dialogs (alert / confirm / beforeunload) are auto-dismissed so the session never hangs on one.
  • flow_replay only replays http/https, times out per request, is capped overall (60 s / 200 steps), and never touches the live browser session.
  • Headers are captured from the actual wire (CDP ExtraInfo), so Cookie and network-added headers are recorded — not just what requestWillBeSent first saw — and net_get shows every one, including custom signing headers (x-api-key, x-signature, agent, …), not just a well-known subset.
  • Dependency detection and secret redaction are best-effort heuristics — review generated code and exported HAR before sharing or running against production. A computed value bfa can't reverse (e.g. a signature like MD5(secret + timestamp)) stays a literal; a failing flow_replay usually means exactly such a header still needs to be reproduced in your own code.

Development

npm run typecheck
npm test          # unit + real-Chrome integration + in-memory MCP e2e
npm run build

License

MIT

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选