Runtime Flow & Architecture
This page walks the whole system: how awebrain process starts, how an MCP
tool call travels from your LLM client to a browser, and where each piece of
runtime behavior lives. It intentionally skips user-facing feature docs (those
are in the guides and reference pages) and focuses on how the code hangs
together.
Top-level shape
Three crates, one binary:webrain-cli— thinmatch-based subcommand entry point (no clap). Owns the binary and the non-MCP CLI (fetch, screenshot, spider, doctor, launch, login, vault, cookies, engine spawning).webrain-mcp— the MCP server: stdio + HTTP transports, the JSON-RPC dispatcher, and the 51-tool schemas + dispatch table.webrain-core— the runtime: CDP client, engines, install, launch, vault, login, vision. Bothwebrain-cliandwebrain-mcpcall into it.
Startup & request flow
1. CLI entrypoint — webrain-cli/src/main.rs
main() sets up tracing (logs to stderr — MCP JSON must never be polluted)
then dispatches on args[1]:
webrain mcp→webrain_mcp::run_stdio()(default) orwebrain_mcp::run_http(addr)when--http <port>is passed.webrain fetch <url>/webrain screenshot <url>/webrain spider <seed>→ attach toCDP_URLand driveCdpBackenddirectly.webrain doctor/--doctor→ full install diagnosis (exits 0 healthy, 2 broken).
2. MCP server — webrain-mcp/src/lib.rs
Two transports, one dispatcher:
run_stdio()— reads newline-delimited JSON-RPC from stdin, oneCdpBackendsession at a time:handle_rpc(msg, &mut backend)→with_token_cost(...)→ write the response line. (lib.rs:669)run_http(addr)— HTTP transport with a per-Mcp-Session-Idbackend map: a session is minted oninitializeand reused when the header matches.
handle_rpc() (lib.rs:51-608). It routes
initialize / notifications / tools/list / tools/call, and intercepts a
handful of tools before the CDP backend is touched because they need no
browser: webrain_guide, webrain_fetch_http, webrain_search,
webrain_download, webrain_pdf_render / webrain_pdf_images.
3. Tool registration — webrain-mcp/src/tools.rs
list_tools()(tools.rs:144-733) — the 51webrain_*schemas the LLM sees, with the canonical descriptions.call_tool()(tools.rs:810-1883) — the dispatch:match tool_name→ resolve aBrowserBackend(usually aCdpBackend), then invoke the core logic. Tools are grouped aroundwebrain_core::engines,webrain_core::backends::cdp,webrain_core::login, andwebrain_core::vision.store_launched()/close_launched()— the launched-browser registry, keyed"service:profile", sowebrain_logincan re-attach to a profile.
Tool execution pipeline
A browser tool call (e.g.webrain_navigate) resolves like this:
BrowserBackend trait
(webrain-core/src/browser.rs) — every engine path implements the same
navigate/eval/click/screenshot/a11y surface, so tools never care which browser
is underneath. Extraction and crawling tools bypass the browser entirely:
webrain_extract_json / webrain_extract_regex / webrain_table /
webrain_autoschema / webrain_bm25 run in-page JS, zero-LLM, and
webrain_fetch_http / webrain_search / webrain_sitemap are pure HTTP.
Browser & engine orchestration
- Install (
webrain-core/src/install.rs):install_chrome()fetches the Chrome for Testing JSON, downloads the platform zip, extracts it underbrowsers_dir()(the engine cache), and returns the binary path (install.rs:383).install_obscura()mirrors it for the Obscura release. - Launch (
webrain-core/src/launch.rs): spawns Chrome / lightpanda / obscura and waits for the CDP endpoint; theLaunchedhandle is kept in the MCP registry. - Engines (
webrain-core/src/engines.rs):http_fetch(no browser),SpiderEngine(BFS/DFS/best-first + autothrottle + checkpoint/resume),TileEngine(vision tiles), extraction + BM25, and download (http + yt-dlp).
CDP backend & browser control
CdpBackend (webrain-core/src/backends/cdp.rs) owns the WebSocket to the
browser. On attach it applies stealth hardening (UA override,
Emulation.setAutomationOverride, JS patches) so it can log into real sites.
It is Clone sharing one WS; batch = a tokio semaphore + one tab per URL.
Sessions pool browsers per session_id for parallel subagent isolation.
Login, vault & challenges
- Vault (
webrain-core/src/vault.rs): credentials encrypted with AES-256-GCM;get/set/removeplus TOTP (totp_code/totp_at). Secrets are decrypted in-process and injected via CDP — never through the model. - Login (
webrain-core/src/login.rs):run_login()is shared by the CLI (webrain login) and the MCPwebrain_logintool. It navigates, evaluates the login JS, then pollshas_session/gate_up— TOTP auto-fill via the vault seed, awaiting_for_human: truereply on a 2FA gate, and a 15s timeout with a clear message (login.rs:96). - Challenges:
webrain_navigatereturns achallengefield on every call. When it is non-null, only real Chrome can pass it —scripts/stealth_solve.pylaunches a stealth Chrome, waits out the proof, logs in, exports cookies, and keeps the browser alive on 9222 so webrain re-attaches to the shared session.

