Tools Reference
All 18 tools are discovered dynamically —webrain_guide lists them for the
LLM. The surface is intent-based (firecrawl-style): each tool has a what
/ action / op / mode selector that routes to the legacy capability via
map_surface(). This page is the authoritative reference; descriptions match
webrain-mcp/src/tools.rs. Eleven page tools declare an optional session_id
(navigate, observe, interact, eval, eval_in_frame, extract, vision,
pdf, crawl, search, serp) that routes the call to a
webrain_open_session pool. The browserless tools do not declare it, and
webrain_batch spreads across browsers with cdp_urls instead.
The accordions below document the legacy one-action tool names (e.g.webrain_click,webrain_snapshot) that still dispatch — they are the executorsmap_surface()routes the consolidated selectors to, so they remain the precise reference for each capability.
Tool-to-code map
The consolidated schemas live inwebrain-mcp/src/tools.rs (list_tools), and
every call routes through call_tool — map_surface(name, args) first folds a
consolidated tool + selector into the legacy arm name, then the existing
match runs. From there tools resolve into webrain-core. The execution
model is simple: browser tools run through CdpBackend (one shared
WebSocket to the engine); a handful of tools skip the browser entirely.
CdpBackend works on Chrome,
lightpanda, and obscura alike — the differences are capability (screenshots,
challenge solving, a11y fidelity), not protocol. Tools with no browser
dependency (webrain_scrape, webrain_search, webrain_serp HTTP engines,
webrain_crawl mode=sitemap,
webrain_download, webrain_pdf, webrain_watch) are intercepted in
webrain-mcp/src/lib.rs handle_rpc before a backend is even attached.
Host
webrain_stats
webrain_stats
/proc (no shell, no sidecar):load— 1/5/15-minute load averages, so a slow job can be told apart from a busy host.memory—total_mbandavailable_mb. Available, not free:MemFreecounts page cache as gone, which reads as an emergency on a healthy box.processes—total, plusbrowser_processescounting engines bycomm(chrome,chromium,headless_shell,obscura,obscura-worker,lightpanda). One Chrome shows up as several (zygote, GPU, renderers), so treat it as a liveness signal, not a tab count.uptime_s— how long the container or host has been up.
available: false means the platform has no /proc (macOS, Windows). That is a fact to report, not a number to invent.Takes no arguments and is read-only. Disk usage is deliberately absent: every way to get it costs either a dependency or a child process, and spawning processes is the thing this tool exists to avoid.Navigate & Observe
webrain_guide
webrain_guide
challenge field after webrain_navigate; persistent profile + real Chrome + session via webrain_session(op=login)), and the extraction tool matrix. Call FIRST when unsure which webrain tool/browser to use.It answers progressively: with no topic you get the tool list plus an index of every section; topic="extraction" (or any section name — case-insensitive substring) returns just that section; topic="all" returns the whole guide. That keeps the “I’m not sure what to do” call at ~800 tokens instead of ~2.7K.topic="skills" lists operator skill files from WEBRAIN_SKILLS_DIR (default <engine cache>/skills), and topic="skill:<name>" returns one — a way to hand the agent house rules (a customer’s conventions, a login procedure) without recompiling. Names are validated (a-z A-Z 0-9 _ -, max 64) so the argument can never carry a path.Two ways to fill that directory:webrain skills add requires a frontmatter name: and refuses files over 64 KiB
— both are the reader’s own restrictions, so a skill that installs is a skill that
can be read.webrain_snapshot
webrain_snapshot
webrain_eval
webrain_eval
webrain_page_info
webrain_page_info
webrain_a11y
webrain_a11y
[{role, name, value, css_path}]. Read-only — understand structure, then interact via webrain_navigate/webrain_snapshot element indices. Filters: role, filter (substring on name OR value OR css_path), max_nodes.ARIA cheat-sheet: combobox (dropdown), option (menu item), tab, radio (segmented control), textbox, button. If role=<x> returns [], drop the role filter and filter on the label text.webrain_semantic_tree
webrain_semantic_tree
role "name" lines for the LLM, plus the raw AX JSON.webrain_get_html
webrain_get_html
webrain_snapshot/clean/eval/extract_json return text/structure cheaper. Only when the task explicitly asks for HTML markup.webrain_console
webrain_console
webrain_screenshot
webrain_screenshot
full_page captures the full scrollable page.format: png (default) | jpeg | webp | avif, plus quality (1-100,
default 80) for the lossy ones. png/jpeg/webp are encoded by the browser itself
(Page.captureScreenshot), so those cost no extra pass. avif has no CDP
encoder: it is captured as png and converted in-process by ravif/rav1e, which
costs a CPU re-encode.Measured, same viewport, two very different pages:webp unless a client needs a
specific type. The reply reports format (what was actually produced) and
requested_format, so a silent fallback is visible.The reply also lands the image as an MCP image content block next to the JSON,
so a client that renders images shows it directly instead of handing the model a
base64 string. The same bytes are written to dir and the path is returned.webrain_annotate
webrain_annotate
[{n, index, tag, text}]. The index maps to webrain_click/webrain_type indices. Built for vision models — read the labels, then click by index. Removes the overlay after capture.Interact
webrain_click
webrain_click
webrain_navigate elements list).webrain_type
webrain_type
ms to type through real per-key Input.dispatchKeyEvent events at that
cadence instead of one Input.insertText paste. insertText fires no
keydown/keyup, which text captchas and the reCAPTCHA/hCaptcha audio challenge
flag as non-human — {"index": 5, "text": "hello", "ms": 60} produces 5
keydowns.webrain_press
webrain_press
webrain_type to submit forms.Keys: Enter Tab Escape Backspace Delete Space ArrowUp/Down/Left/Right
Home End PageUp PageDown Insert.key also accepts a shortcut — ctrl+a, shift+Tab, meta+v,
alt+ArrowLeft. The modifier bitmask rides on both keyDown and keyUp and the
base key carries a real code (KeyA), which is what makes an accelerator bind
and what clears a prefilled captcha field or tabs through an audio challenge.
Enter keeps the JS path that dispatches form.submit(); a modified Enter does
not submit.webrain_scroll
webrain_scroll
direction: up | down.With x, y and an optional delta it wheels the element under that point
instead of the window — the only way to move a captcha modal, an inner list or a
scrollable side panel. delta is signed (negative scrolls up); default ±500.webrain_tab
webrain_tab
new (url, returns id, becomes active) | switch (id) | close (id) | list.webrain_dismiss_overlays
webrain_dismiss_overlays
webrain_select
webrain_select
<select> dropdown by index: matches by option value OR visible text, fires a real change event. No-match errors and lists the available options so the LLM self-corrects.webrain_hover
webrain_hover
mouseMoved. Triggers CSS :hover menus, tooltips, and lazy hover-reveal content.webrain_check
webrain_check
webrain_dialog
webrain_dialog
alert/confirm/prompt). A sync alert() pauses the page — every click/eval hangs until this resolves it. action: accept | dismiss (optional prompt_text). Works even while the renderer is paused.webrain_wait
webrain_wait
ms, or poll until a selector or visible-text substring appears (default timeout 15s). navigate already waits internally — this is for click→AJAX→render steps. Returns satisfied: bool.webrain_upload
webrain_upload
DOM.setFileInputFiles. Index must be an <input type=file>.webrain_click_coords
webrain_click_coords
webrain_page_info.webrain_drag
webrain_drag
x1,y1 → x2,y2): approach the handle,
press, dwell, trace an eased path with the button held, settle on the target,
release — all via CDP Input events. Built for slider/drag CAPTCHAs (“slide to
unlock”, GeeTest, DataDome, AWS WAF) and it works across cross-origin iframes
where synthetic JS events are ignored. Get coords from a screenshot
(webrain_observe what=screenshot) or webrain_page_info.ms sets how long the handle is held before the movement starts (default
150). A zero-length drag (x1==x2, y1==y2) with ms is therefore a
press-and-hold in place.webrain_hold
webrain_hold
(x, y) for ms, then release — for “Press & Hold to
confirm you are a human” widgets (PerimeterX/HUMAN). Those only fire after a
multi-second mousedown, so a click or a short drag never registers. Default 6 s.action=hold, or the equivalent zero-length
drag (x1==x2, y1==y2, ms).webrain_add_init_script
webrain_add_init_script
Page.addScriptToEvaluateOnNewDocument). Use for closed-shadow-root piercing, API stubs, or route/UA overrides. Accumulates for the session.Extract
webrain_autoschema
webrain_autoschema
webrain_extract_json schema. Zero LLM. min_occurrences (default 3).webrain_extract_json
webrain_extract_json
type: text | attr | html | xpath. adaptive: true auto-relocates the container when the base selector matches nothing (site redesigned).webrain_extract_regex
webrain_extract_regex
[{label, re}]. Scans page HTML (catches href/mailto).webrain_table
webrain_table
{header: cell} row objects per <table>. Zero LLM.webrain_get_jsonld
webrain_get_jsonld
<script type="application/ld+json"> blocks — schema.org product/article/organization data. Zero LLM, zero cost.webrain_bm25
webrain_bm25
webrain_clean
webrain_clean
webrain_fit
webrain_fit
webrain_flatten
webrain_flatten
querySelectorAll/innerText miss. Resolves slots, recurses open shadow roots. Use when a page looks empty.Crawl & Batch
webrain_batch
webrain_batch
op: fetch (read text) | markdown (full page as Markdown) | extract (CSS schema: base_selector+fields) | autoschema (propose base selectors per URL — the step that produces a base_selector for extract, same in-page heuristic as webrain_extract{mode:"autoschema"}, min_occurrences default 3) | interact (async JS interaction, then optional extract) | eval (run JS in each tab) | screenshot (save PNGs to dir).cdp_urls fans out across N CDP backends round-robin (per-proxy isolation). output persists the full payload to disk. Optional disable_resources, network_idle, wait_selector shared with navigate.webrain_spider
webrain_spider
allow/deny URL-regex filters, retry, delay_ms, autothrottle (adaptive backoff), crawldir checkpoint/resume (persists {queue, seen, results} atomically; resume returns prior + new, never re-fetches; max_pages counts the whole crawldir), concurrency (parallel tabs on Chrome/obscura, default 4), crawl_timeout_secs.webrain_sitemap
webrain_sitemap
Sitemap: → index → leaf sitemaps → every <loc>. Pure HTTP, no browser. Returns {urls, count, sources}.webrain_scan
webrain_scan
{scrolls, height}. Run before extraction on SPA feeds.webrain_validate_urls
webrain_validate_urls
webrain_fetch_http
webrain_fetch_http
{url, status, text}. 10–100× faster than browser navigation, zero memory — but no JS/SPA/auth. Use for static pages.Search
webrain_search
webrain_search
duckduckgo is HTML-lite and scrape-friendly (default); google and bing return plain HTML via HTTP; brave returns an SPA shell — use webrain_navigate to Brave’s URL instead for real results.webrain_serp
webrain_serp
position/title/url/domain/snippet) — a SERP API any LLM can call. duckduckgo (default) / bing are plain HTML over the pooled no-browser HTTP agent; google is JS-gated over HTTP so it uses the browser path — webrain serp --engine google auto-launches a persistent-profile Chrome (headed by default, --headless for headless) and drives homepage → consent (trusted two-phase click) → humanized typing → trusted click; brave uses its keyed API when BRAVE_API_KEY is set (no browser needed — 20/page, page-indexed offset), otherwise it renders in the connected CDP engine; auto fetches HTTP engines concurrently and merges + dedupes.Built-in: provider fallback (fallback), URL dedupe, pagination (page), safe (safe) + region (region — an en-US market is pinned when unset, because a GeoIP’d IP otherwise serves localized garbage), request_id + ms, retry with backoff (retries), and a multi-page merge so limit > ~10 is honored wherever engines paginate.Proxy: proxy routes the HTTP engines through an HTTP(S)/SOCKS proxy (e.g. http://user:pass@host:port) and bakes --proxy-server into the google auto-launch. Bing/Google GeoIP-lock flagged/rotating IPs and ignore market params, so a clean-IP proxy is the reliable way to get correct, larger result sets. An attached CDP engine keeps whatever proxy it started with.CAPTCHA walls: detected, never solved automatically. webrain_navigate reports challenge (cloudflare_challenge · captcha · blocked) so the agent stops instead of extracting a challenge page; passing one needs real Chrome + a persistent profile + an interactive webrain login.Brave API: set BRAVE_API_KEY and engine=brave goes through api.search.brave.com — typed JSON, 20 results per page, no browser at all; auto engages it for limit > 20 while still short, before any browser render.serpapi.com: set the standard SERPAPI_API_KEY env var. It’s the reliable way to get MORE than the free engines’ ~10-result cap — serpapi honors num up to 100 — so for limit > 10 it’s tried first for google (the full best result set); for limit <= 10 the free browser path stays primary and serpapi is a fallback. Unset key / quota-exhausted / 4xx degrades to the normal fallback with no error.webrain serp "query" [--engine …] [--limit N] [--page N] [--safe] [--region R] [--no-fallback] [--json] [--headless] [--proxy URL] [--fresh] [--pipe] [--stealth] [--hold].Proxy routing — three places
proxy always wins over WEBRAIN_PROXIES; the pool is only the fallback, and it is process-global — never share it between tenants. A browser tab’s exit is fixed when its browser or context is created, so “change proxy on a live browser” means re-opening the session_id with a different proxy (new context + tab, same Chrome process) — not mutating the existing one. A new context is a fresh profile: keep_identity:true copies cookies only, so an SPA that keeps its token in localStorage/IndexedDB still logs out. Where an IP change is a fraud signal (banks, Google, Stripe), pin one exit per profile and relaunch with the same <service>/<profile> — the on-disk profile keeps the identity, and --proxy-server is the guaranteed path on every engine.Default (google) = warm persistent profile + session — the real bypass path (see skills/webrain/references/challenges.md): the auto-launched Chrome stays alive on 9222 between runs, accumulating consent/session cookies until it becomes a trusted Google profile. --fresh opts OUT of the warm session: it always launches a brand-new profile + cookies on a free port, so the consent modal always renders and is always dismissed before the humanized flow — use it when you want deterministic consent (e.g. a suspect/stale profile). --hold keeps the launched Chrome open after the search so you can watch it (press Enter to close). --pipe (with --fresh) launches that Chrome via --remote-debugging-pipe (NO open debugging port — the open port is the automation fingerprint Google walls on /sorry; note Chrome’s pipe CDP is broken on Windows, works on Linux/macOS). --stealth opts IN to the launch-flag stealth (--disable-blink-features=AutomationControlled); the default is a plain launch + CDP-level masking (patchright/browsemind’s recommended combo). All google human-like actions are trusted CDP input (Input.dispatchMouseEvent/Input.dispatchKeyEvent), never JS-driven.Vision
webrain_pixel
webrain_pixel
tile_width/tile_height (800), max_tiles (16).webrain_vision_index
webrain_vision_index
EMBED_URL (OpenAI-compatible /embeddings), and add to a cosine index persisted to vision/{tag}.jsonl. With the bundled local vision model (webrain install vision), the response also includes vision — a Qwen3-VL-2B page caption via llama-server (real understanding).webrain_vision_retrieve
webrain_vision_retrieve
tag, query, k (5).webrain_vision (op=ask)
webrain_vision (op=ask)
OPENROUTER_API_KEY (Qwen3.6-27B) → OPENAI_API_KEY → FIREWORKS_API_KEY → GROQ_API_KEY → bundled local Qwen3-VL-2B (webrain install vision) — a 27B cloud model reads captcha tiles the local 2B misreads, and a flaky provider fails over to the next.clipx,y,w,h(default: full viewport), optionalscale(2-3× upscale for small tiles; the answer’s coords divide byscaleto get viewport px).tiles: array of{x,y,w,h}clips sent in ONE request as numbered images — the batched precision pass for grid captchas (1 call, not N). Keepscale:2on cloud models;scale:3only helps the weak local 2B.- Note: Qwen3 dumps a long
<think>that truncates multi-image answers in tool results and misreads distorted text — for text/assemble puzzles read each tile as its OWN single-imageop=ask.
webrain_eval_in_frame
webrain_eval_in_frame
url_contains src substring) via a CDP isolated world — the only way to read exact geometry inside reCAPTCHA/hCaptcha/Turnstile/2captcha challenge frames (grid tile rects, verify button, shared sprite data-URLs) that webrain_eval cannot reach. Returns the expression’s JSON value (string results need parsing). Same-origin iframes can be reached with plain webrain_eval via contentDocument. See workflows/captcha-solve.md for the exact puzzle-geometry expressions.webrain_watch
webrain_watch
detail transcript/efficient/balanced; batch sources[] in parallel. vision:true sends up to 3 sampled frames to a vision LLM (Groq qwen3.6-27b → OpenAI gpt-4o-mini → local Qwen3-VL-2B when no key) and returns text captions + a fused visual summary in vision. First run: webrain install watch (mono bundle) + webrain install vision for the local hero.PDF & Media
webrain_pdf
webrain_pdf
webrain_pdf_extract
webrain_pdf_extract
pdf_type (TextBased/Scanned/Mixed), confidence, layout (is_complex, pages with tables/columns), full markdown, and per-page texts. Proper ToUnicode CMap decoding fixes LaTeX/CID-font PDFs. Single path or batch paths.webrain_pdf_render
webrain_pdf_render
tile_size splits each page into square tiles; every entry carries page, x, y, w, h. Requires a --features pdfium build and pdfium.dll / libpdfium.so on PATH. Prebuilt binaries ship without pdfium, so op=render errors there — use op=extract for text and tables, op=images for embedded figures, or open the PDF in Chrome and webrain_observe what=screenshot for a raster.webrain_pdf_images
webrain_pdf_images
webrain_pdf_render for those). Works in the default build.webrain_download
webrain_download
engine http (plain streaming, optional filter_extension) or ytdlp (HLS/DASH/.m3u8, playlists, age/cookie-bound media — full yt-dlp passthrough via args).webrain_media
webrain_media
url: CDP Network capture of the full load — catches JS-loaded .m3u8/.mp4/manifest/player-API requests. Without: Performance API + <video>/<audio>/<source> scan of the current page.webrain_get_images
webrain_get_images
[{src, alt, width, height}]. Useful for product/photo URLs.Auth & Sessions
webrain_login
webrain_login
WEBRAIN_USER/WEBRAIN_PASS): the server decrypts the secret in-process and injects it via CDP — the value never passes through the model. Auto-discovers login fields; on a 2FA gate it TOTP-injects if a seed is stored and returns waiting_for_human: true. Reply is status-only.webrain_profiles
webrain_profiles
webrain_save_state
webrain_save_state
<profiles_dir>/<service>/<profile>/state.json so a login follows you across machines.webrain_restore_state
webrain_restore_state
<profiles_dir>/<service>/<profile>/state.json into the current browser. Navigate to the target site first — localStorage is origin-scoped.webrain_open_session
webrain_open_session
webrain_batch/webrain_navigate calls to it via session_id — use different sessions to isolate tasks or browsers (e.g. one per CDP_URL for parallel subagents).webrain_close_session
webrain_close_session
default session cannot be closed.webrain_list_sessions
webrain_list_sessions
webrain_close_launch
webrain_close_launch
webrain launch (kills the browser process; the persistent profile + cookies remain for the next launch).
