Public Browser
Provides tools for automating Chrome browser via the DevTools Protocol, enabling actions like navigating pages, clicking, typing, form filling, and more.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Public BrowserNavigate to example.com and click the first link."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Public Browser
The most token-efficient MCP server for Chrome browser automation. Direct CDP, a11y-tree refs, multi-tab ready — 2300+ TypeScript tests, 237 Python tests.
Built for Claude Code, Cursor, and any MCP-compatible client.
Looking for an alternative to Playwright MCP, Browser MCP, or claude-in-chrome? Public Browser talks to Chrome directly via the DevTools Protocol — no Playwright dependency, no Chrome extension bridge, no single-tab limit. One command to install, zero config. See benchmark comparison below.
Why Public Browser?
Every Chrome MCP server has the same problem: too many tokens, too few reliable refs. Screenshots eat 10-30x more tokens than text trees. Selector-based refs break the second the DOM rerenders. Extension bridges (Browser MCP) get stuck on the connected tab. Playwright wrappers spin up a new browser instance for every session.
Public Browser fixes this. It talks directly to Chrome via CDP (same protocol Playwright and Puppeteer use internally), returns an accessibility-tree-based reference map, and caches it across calls so click(ref: 'e5') and type(ref: 'e7', ...) survive scrolls and DOM updates.
What you get | Playwright MCP | Browser MCP | claude-in-chrome | browser-use | Public Browser |
Benchmark pass rate (31 scorable tests, LLM-driven) | 29/31 (563s) | 6/31, aborted | (24-test suite only) | 21/31 (1870s) | 30/31 (598s) |
Avg Tool-Response (Tokens est.) | 362 | — | — | — | 201 (1.8x smaller) |
P95 Tool-Response (Chars) | 8,068 | — | — | — | 2,328 (3.5x smaller) |
| 6,084 ( | — | — | — | 1,124 (5.4x smaller) |
Multi-tab support | Yes | No (single tab) | Yes | Partial | Yes |
Connection | New browser | Extension bridge | Extension | Subprocess | Direct CDP (pipe or WebSocket) |
Ref system | Playwright refs | Playwright refs | CSS selectors | Screenshots | A11y-tree refs (stable across DOM changes) |
Drag & drop | Yes | No | Partial | No | Yes (native CDP mouse events) |
Shadow DOM + iframe | Yes | Yes | Partial | No | Yes (with OOPIF session support) |
Multi-step plan execution | — | — | — | — |
|
Related MCP server: chrome-devtools-slim
Quick Start
Install in Claude Code
One command — installs globally for all projects:
claude mcp add --scope user public-browser npx -y public-browser@latestImportant: after claude mcp add you must fully quit and reopen Claude Code. /mcp reconnect is not enough — Claude Code reads the mcpServers config only at session start and caches it. After the restart, the first tool call auto-launches Chrome visible (no headless, no port setup). Done.
To enable parallel Python Script API access, add
--scriptto the args:claude mcp add --scope user public-browser npx -y public-browser@latest -- --script
Install in Cursor
Add to ~/.cursor/mcp.json:
{
"mcpServers": {
"public-browser": {
"command": "npx",
"args": ["-y", "public-browser@latest"]
}
}
}For parallel Python Script API access, use
"args": ["-y", "public-browser@latest", "--", "--script"]
Install in Cline
Add to your cline_mcp_settings.json:
{
"mcpServers": {
"public-browser": {
"command": "npx",
"args": ["-y", "public-browser@latest"]
}
}
}Install in other MCP clients
Any client that supports stdio MCP servers: npx -y public-browser@latest with no arguments.
Try it — your first prompt
After installing, paste this into your AI coding assistant:
Open mcp-test.second-truth.com, read the page, and fill the contact form with Name "Test User" and Email "test@example.com".
This exercises three core tools in sequence: navigate loads the page, view_page reads the accessibility tree with stable element refs, and fill_form fills multiple fields in one call. You should see Chrome open, the page load, and the form filled — all without writing a single line of code.
Uninstall
claude mcp remove --scope user public-browserChrome Profiles
By default, Public Browser starts Chrome with a fresh temp profile — no cookies, no logins, no extensions. For tasks like research on sites that block anonymous visitors, you can launch Chrome with your real profile instead.
List available profiles
npx public-browser profilesLaunch with a profile
Three ways — pick whichever fits your setup:
# CLI flag
npx public-browser --profile "Julian"
# Environment variable
PUBLIC_BROWSER_PROFILE="Julian" npx public-browser
# MCP tool (call BEFORE any browser interaction)
configure_session({ profile: "Julian" })When using a real profile, Public Browser preserves extensions, cookies, logins, and sync. It creates a lightweight wrapper directory with a symlink to your real profile data — Chrome gets a "non-default" data dir (required for remote debugging) while using your actual profile.
If Chrome is already open
Public Browser detects this via lock-file inspection. If Chrome is running with remote debugging enabled, it attaches via CDP. If not, it shows a clear error asking you to close Chrome first.
Script API (Python)
A second way to use Public Browser — deterministic browser automation from Python, without an LLM in the loop. Scripts use the same tool implementations as the MCP server (Shared Core) — every improvement to click, navigate, fill_form etc. automatically benefits your scripts too. The MCP server handles AI-driven workflows; the Script API is for repeatable scripts you write yourself.
How fast that is without an LLM: a scripted run of the 24-test version of the benchmark suite finished the whole suite in 21 seconds (type: mcp-scripted, 2026-04-04). That number says what deterministic scripting costs, not how Public Browser compares to other MCP servers — every cross-server comparison in Benchmarks is LLM-driven on both sides.
Installation
The Python package is not currently published on PyPI. From a source checkout, install the local package:
python -m pip install ./pythonChrome.connect() auto-starts the Public Browser server as a subprocess via a local public-browser binary or the npx fallback — no manual Chrome launch or port setup needed.
Legacy single-file alternative: For quick prototyping you can copy
python/silbercuechrome.pyinto your project. This uses v1 direct CDP and does not benefit from server-side improvements — use the localpublicbrowserpackage for the full Shared Core experience.
How it works
Python Script Escape Hatch (Power User)
| |
v v
HTTP POST /tool/{name} WebSocket (CDP)
Port 9223 Port 9222
| |
v |
Public Browser Server |
| |
v |
registry.executeTool() |
| |
v |
Tool Handler |
(click.ts, navigate.ts, ...) |
| |
v v
Chrome <------------ CDP --------------->Your script sends HTTP requests to the Public Browser server on port 9223. The server executes the exact same tool handlers that the MCP server uses — one codebase, one test suite (2300+ tests), two access paths.
Auto-Start
Chrome.connect() finds and starts the server automatically:
Running server — checks if port 9223 already responds, connects immediately
PATH binary — finds
public-browserin PATH, starts it with--scriptnpx fallback — runs
npx -y public-browser@latest -- --scriptExplicit path —
Chrome.connect(server_path="/path/to/public-browser")for custom setups
Example: Login + Data Extraction
from publicbrowser import Chrome
chrome = Chrome.connect()
with chrome.new_page() as page:
page.navigate("https://competitor.example.com/login")
page.fill({"#email": "tomek@shop.de", "#password": "***"})
page.click("button[type=submit]")
page.wait_for("text=Dashboard")
for cat in ["electronics", "furniture", "toys"]:
page.navigate(f"https://competitor.example.com/prices/{cat}")
prices = page.evaluate(
"[...document.querySelectorAll('tr')].map(r => r.textContent)"
)
save_csv(cat, prices)
chrome.close()Methods
Method | Description |
| Connect to or auto-start the Public Browser server |
| Context manager — opens a new tab, auto-closes on exit |
| Navigate and wait for load |
| Click element by CSS selector, text, or ref |
| Type text into an input |
| Fill multiple form fields at once |
| Wait for JS condition or |
| Run JavaScript, return result |
| Enable downloads, return download dir |
| Close the tab (auto-called by context manager) |
| Escape Hatch — direct CDP access via WebSocket (see below) |
Escape Hatch: Direct CDP Access
For use cases the high-level API doesn't cover — network interception, console log subscriptions, performance tracing, cookie management — you can drop down to raw CDP commands:
with chrome.new_page() as page:
page.navigate("https://example.com")
# Enable network tracking
page.cdp.send("Network.enable")
# Get all cookies
cookies = page.cdp.send("Network.getAllCookies")
# Performance tracing
page.cdp.send("Tracing.start", {"categories": "-*,devtools.timeline"})The Escape Hatch communicates directly with Chrome via WebSocket (port 9222), bypassing the server. It connects lazily on the first send() call and reuses the connection for subsequent calls. Each page gets its own WebSocket routed to the correct tab.
MCP Coexistence
When the MCP server and Python scripts need to run at the same time, add --script to the MCP config. Chrome.connect() handles the rest automatically — each script works in its own tab, MCP tabs are never touched.
Enabling --script in MCP Config
Claude Code:
claude mcp add --scope user public-browser npx -y public-browser@latest -- --scriptCursor / Cline (mcp.json):
{
"mcpServers": {
"public-browser": {
"command": "npx",
"args": ["-y", "public-browser@latest", "--", "--script"]
}
}
}See python/README.md for the full API reference and advanced examples.
Node Library API (multiple instances in one process)
The MCP server and the Python Script API both drive exactly one Chrome per
process. When you need several browsers at once — say a read-only research
browser and a separate action browser per agent — spawning one
npx public-browser per instance costs 4–6 s of start-up each. createSession()
runs the same session inside your own Node process instead:
import { createSession } from "public-browser";
const research = await createSession({
cdpUrl: "http://127.0.0.1:9333", // or cdpPort: 9333
userDataDir: "/var/agents/a1/research", // created if missing
headless: true,
stealth: false, // stay identifiable — see below
downloadDir: "/var/agents/a1/quarantine", // never deleted by us
downloadHash: true, // adds sha256 to every download
downloadNaming: "suggested", // real filenames, not GUIDs
cortexDir: "/var/agents/a1/cortex", // per-instance pattern store
inheritEnv: ["HTTPS_PROXY"], // opt in — see Environment below
});
const action = await createSession({ cdpPort: 9334, userDataDir: "/var/agents/a1/action" });
await research.callTool("navigate", { url: "https://example.com" });
const page = await research.callTool("view_page", {});
await research.close();
await action.close();callTool(name, params) takes the same tool names and parameters as the MCP
tools (navigate, view_page, click, type, fill_form, run_plan,
download, ...) and routes through the identical handlers (Shared Core).
Isolation. Each session runs in its own worker thread by default, so the module-level caches (element refs, selector cache, viewport state, stealth flag, cortex matcher) exist once per session rather than once per process — two sessions can never hand each other stale element refs.
Measured on macOS with isolation: "process", attaching to a Chrome started
outside Public Browser (a worker thread saves ~40 ms):
Median | |
| ~0.9 s |
| ~0.7 s |
...through to a real page navigated and read | ~1.8 s |
Most of the attach cost is Chrome starting a renderer for the tab Public Browser opens for itself — an attached session never takes over tabs that belong to someone else.
A thread is not a security boundary: same process memory, same file
descriptors. isolation: "process" forks one OS process per session instead —
separate heap, separate descriptors, separate crash domain — for integrators
whose trust model draws the line there. isolation: "inline" skips isolation
altogether and is only correct when the thread runs exactly one session.
| Boundary | Startup | Use when |
| thread — private module caches | ~1 s | several sessions in one trusted process |
| OS process — private memory + descriptors | ~1 s | the sessions must not share a process with the host |
| none — the calling thread | fastest | exactly one session per thread |
No listening CDP port (transport: "pipe"). By default Chrome is launched
with --remote-debugging-port, which is what makes --attach, the Script API
and reconnect-after-crash possible — and which also means every other process
on the machine can drive that browser. For a session holding real logins that
is a way around any permission check you perform yourself.
const action = await createSession({
transport: "pipe", // no --remote-debugging-port at all
userDataDir: "/var/agents/a1/action",
headless: true,
});CDP then travels over the child's stdio pipe, which only Public Browser holds:
lsof shows nothing listening and a second process finds no way in. The price
is everything the port paid for — no reconnect after a Chrome crash, no second
client, no attach, and no named profile (Chrome rejects the pipe with a
real user profile). Both contradictions fail at createSession() rather than
at the first tool call. session.transport reports which mode is in use, and
session.cdpPort is undefined — there is no port, and reporting the default
would name whatever Chrome the user has open on 9222.
Environment. A session does not start from the host environment. It starts from a documented minimum and you widen it deliberately — an orchestrator holding cloud credentials, API keys and tokens should not hand them to a browser session just because the two share a process tree.
What a session always gets is ESSENTIAL_ENV_VARS: PATH, HOME, the temp
dir, CHROME_PATH, locale/timezone, the Linux display variables and the
Windows process basics. Everything else is opt-in:
// PATH/HOME/CHROME_PATH plus the proxy — and nothing else from the host.
await createSession({ inheritEnv: ["HTTPS_PROXY", "NO_PROXY"] });
// Full inheritance, the pre-2.8 behaviour.
await createSession({ inheritEnv: true });Proxy variables are deliberately not essential: a proxy URL can carry credentials, so it is allowlisted on purpose rather than inherited by accident.
On top of that, a session never inherits Public Browser's own SILBERCUE_* /
PUBLIC_BROWSER_* configuration variables — in any inheritEnv mode. Each of
them has an option here, and a host-level variable, usually set for the host's
own Chrome, silently redirecting a configured session is a bug, not a feature:
with SILBERCUE_CHROME_HOST=10.9.9.9 in the orchestrator's environment, a
session created with cdpPort: 9450 still talks to 127.0.0.1:9450. Use env
to set one back deliberately.
Shutdown. close() resolves only once Chrome is actually gone — SIGTERM,
SIGKILL after 5 s — so the port and the user-data-dir are free for the next
launch instead of racing a process that was merely asked to exit.
One session per Chrome. Some CDP settings are browser-wide rather than
per-session, Browser.setDownloadBehavior among them: two sessions attached to
the same Chrome share one download directory, and whichever connected last
wins.
This fails silently and it corrupts the record: the losing session keeps
reporting paths under its downloadDir, but the file was written to the
other one. path then points at nothing, with no error to notice. Give each
session its own Chrome — its own port (or transport: "pipe") and its own
user-data-dir — whenever downloadDir matters.
Option | Default | Description |
| — |
|
|
| CDP endpoint this session drives. |
| — | Chrome |
| — | Named Chrome profile instead of a raw directory |
|
| Launch Chrome headless |
|
|
|
|
| Never auto-launch; attach to a running Chrome and fail fast if there is none |
| temp dir | Where downloads land. A directory you supply is never deleted |
|
| Report |
|
|
|
|
| Per-instance cortex store |
|
|
|
|
| Essentials only. Array = essentials + allowlist, |
| — | Extra environment variables for the session, applied last |
|
|
|
|
| Launch/attach during |
|
| Budget for the session thread/process to report ready |
Multiple instances via the CLI
The same thing without a Node host — one process per Chrome, each on its own port:
public-browser --port 9333 --profile research --download-dir /q/research
public-browser --port 9334 --profile action --download-dir /q/action--profile <name> uses one of your real Chrome profiles. For a throwaway
per-agent Chrome, point at a raw directory instead — it is created if missing:
public-browser --port 9335 --user-data-dir /var/agents/a3/chrome--attach connects to an already-running Chrome on the configured port instead
of launching one. SILBERCUE_CHROME_PORT and SILBERCUE_SCRIPT_PORT are the
environment equivalents of --port and --script-port and are part of the
stable public contract.
Identifiable automation (--no-stealth)
By default Public Browser masks navigator.webdriver (it reports undefined)
and launches Chrome with --disable-blink-features=AutomationControlled. That
is the right default for consumer automation, but the wrong one when your
integration must be transparently identifiable as a bot — compliance-driven
crawling, internal agent fleets, or sites whose terms require honest signalling.
Turn the masking off completely:
public-browser --no-stealth
# or
SILBERCUE_STEALTH=0 npx public-browserawait createSession({ stealth: false });With stealth off, navigator.webdriver stays true and keeps its native
getter (Object.getOwnPropertyDescriptor(Navigator.prototype, "webdriver").get
still reports [native code]) — permanently, across navigations and tab
switches, with no post-correction needed on your side. No masking script is
injected at any point and the launch flag is omitted.
Downloads
Downloads land in a per-session temp directory that is removed on shutdown.
Point them at a directory of your own — a quarantine dir, a shared volume — with
--download-dir / PUBLIC_BROWSER_DOWNLOAD_DIR / downloadDir. A directory you
supply is created if missing and never deleted by Public Browser.
With --download-hash (or downloadHash: true) every completed download also
carries a sha256, so the download tool returns path, size and digest:
{"filename":"report.pdf","path":"/q/research/A1B2...","size":48213,"sizeKb":48,
"url":"https://example.com/report.pdf","sha256":"9f86d081884c7d659a2f..."}Filenames. Chrome writes downloads under their internal GUID, so the file on
disk is called A1B2... and only the filename field carries the real name.
That is fine when you read the JSON, and useless when something else has to walk
the directory. --download-naming suggested (or downloadNaming: "suggested",
PUBLIC_BROWSER_DOWNLOAD_NAMING=suggested) renames each finished file to the
server-supplied name:
{"filename":"report.pdf","path":"/q/research/report.pdf","size":48213,"sizeKb":48,
"url":"https://example.com/report.pdf","sha256":"9f86d081884c7d659a2f..."}The name is sanitised before it touches the disk — basename only, no control
characters, never hidden, length-capped — and a collision gets a -1, -2, ...
suffix rather than overwriting an existing file. filename always reports the
name the file actually has, so join(downloadDir, filename) equals path. If
the rename fails, the GUID path and the raw server name are kept and reported;
a download is never lost to a naming problem.
Timing. action: "status" waits up to 250 ms for a download to start
before reporting that there is none, because Chrome fires downloadWillBegin a
few milliseconds after the click that triggers it — without the window, the
first call after a click misses a file that is already on its way. Adjust it per
call with settle ({"action":"status","settle":0} for an instant check,
5000 for a slow server). Once a download has started, status waits for it to
finish, bounded by timeout.
For polling loops use action: "list" — it returns the full session history
immediately and never waits, for either a start or a completion.
Tool Overview
Tool | Description |
Reading & Observation | |
| A11y-tree with stable |
| WebP screenshot, max 800px, <100KB. For visual verification only — refs come from |
| Browser console output with level/pattern filters |
| Start/stop/query network requests with filtering |
| Watch DOM changes: |
| Wait for element visible, page text, URL, network idle, or JS expression. |
| Active tab's cached URL/title/ready/errors (0ms) |
| Lists all tabs with stable IDs. Call first in every session. |
| Bounding boxes, computed styles, paint order. For spatial questions |
Interaction | |
| Real CDP mouse events by ref, selector, text, or coordinates. Response includes DOM diff (NEW/REMOVED/CHANGED). |
| Type into an input by ref/selector |
| Fill a complete form in one call — text, |
| Real CDP keyboard events — Enter, Escape, Tab, arrows, shortcuts (Ctrl+K, etc.) |
| Scroll page, element into view, or inside a specific container |
| Upload file(s) to |
| Configure |
| Native CDP drag & drop between elements |
| Enable downloads, return download dir |
Navigation | |
| Load a URL. First call per session auto-redirected to |
| Open, switch to, or close tabs by ID from |
Scripting | |
| Multi-step batch execution with variables, conditions, |
| View/set session defaults (tab, timeout) and accept auto-promote suggestions |
| Visit multiple URLs sequentially and run the same JavaScript expression on each page. |
| Write large payloads to |
| Execute JS in page context. Anti-pattern scanner warns on |
Benchmarks
Measured on https://mcp-test.second-truth.com against the 35-test version of the suite (April 2026) — 5 levels (Basics, Intermediate, Advanced, Hardest, Community Pain Points). Four of the 35 tests are runner-only and are excluded from every score, so all pass rates below are out of 31 scorable tests. The live suite has since grown to 42 tests in 6 levels; the numbers here are not re-measured against it, and cross-server comparisons are only valid within the same suite version. Each run is independent, values on the benchmark page are randomized per page-load, all runs started in a fresh Claude Code session out of /tmp (no project context bias), and all metrics measured post-hoc from the session JSONL via test-hardest/measure-tool-calls.sh — no self-reporting, no MCP-side instrumentation, just counting tool_use blocks and tool_result char lengths.
Head-to-Head (24-test suite, April 2026 — historical suite version)
All rows LLM-driven by Claude Opus 4.6 on the same test page, one recorded run each. Public Browser ran 2026-04-05, the other servers 2026-04-02. This is the older 24-test version of the suite — do not compare these rows against the 31-scorable-test numbers below.
MCP Server | Tests Passed | Duration | Tool Calls | Speed vs PB |
Public Browser | 24/24 | 350s | 71 | -- |
Playwright MCP | 24/24 | 570s | 138 | 1.6x slower |
browser-use skill | 24/24 | 725s | 117 | 2.1x slower |
claude-in-chrome | 24/24 | 772s | 193 | 2.2x slower |
browser-use | 16/24 | 1813s | 124 | 5.2x slower |
Public Browser needed 71 tool calls where Playwright MCP needed 138 — roughly half the roundtrips for the
same 24 passes. Raw data: test-hardest/benchmark-*.json (Public Browser row:
benchmark-silbercuechrome_mcp-llm-2026-04-05.json, type: llm-driven).
Pass Rate + Duration (31 scorable tests, LLM-driven)
Every row is one recorded run; the run id is named so each number is traceable to a single entry in
test-hardest/BENCHMARK-PROTOCOL.md. No averaging across runs.
MCP | Passed | Duration | Run |
Public Browser | 30/31 (97%) | 598s | Run 5 |
Playwright MCP | 29/31 (94%) | 563s | Run 2 |
Playwright CLI | 28/31 (90%) | 376s | Run 1 |
Chrome DevTools MCP (Google) | 27/31 (87%) | 535s | Run 2 |
browser-use | 21/31 (68%) | 1870s | Run 5 |
Browser MCP (browsermcp) | 6/31 (19%) | 294s, aborted | Run 1 |
claude-in-chrome | 24-test data only, not re-benched | — | — |
Servers with several recorded runs, so you can see the spread rather than only the row above: Playwright MCP ranges 29–30/31 across four runs, its best being 30/31 in 449s (Run 3); Chrome DevTools MCP ranges 27–29/31, its best 29/31 in 518s (Run 1). Run 2 is quoted for both because that is the run the tool-efficiency analysis below instruments end to end. On pass rate this field is effectively a tie — the durable difference is response size, and that holds across every Playwright run measured (avg 1,216–1,467 chars in Runs 2–4).
Tool-Efficiency (the fair metric)
We measure each tool call's response char length directly, group by tool name, estimate tokens via chars/4. Why this metric: session-level token deltas are dominated by LLM overhead (system prompt + CLAUDE.md + conversation history = ~80-90% of the budget) and only show 5-15% differences between MCPs — untrustworthy for comparing browser servers. Tool-response size is the part the MCP server actually controls.
Public Browser Run 5 vs Playwright MCP Run 2 — the same two runs as the pass-rate table above.
Metric | Public Browser | Playwright MCP | Difference |
Tool calls (MCP-only) | 151 | 121 | +25% (PB uses more, smaller calls) |
Avg Response size | 807 Chars | 1,448 Chars | PB 1.8x smaller |
Avg Response tokens est. | 201 | 362 | PB 1.8x smaller |
P95 Response | 2,328 Chars | 8,068 Chars | PB 3.5x smaller |
Total response content | 128k Chars | 175k Chars | PB 27% less |
Per-Tool Breakdown (where the difference comes from)
Tool | Public Browser Avg | Playwright MCP Avg | Verdict |
| 1,124 Chars (21 calls) | 6,084 Chars (8 calls) | PB 5.4x more compact per call |
| 510 Chars (33 calls) | 2,155 Chars (47 calls) | PB 4.2x more compact per call |
| 88 Chars (13 calls) | 147 Chars (13 calls) | PB 1.7x more compact |
| 1,278 Chars (63 calls) | 463 Chars (44 calls) | Playwright 2.8x leaner — but see trade-off below |
¹ recorded as read_page in the April 2026 runs; the tool was renamed to view_page afterwards.
The Ambient-Context trade-off
Ambient Context — Claude sees DOM changes for free, no extra
view_pageneeded
Public Browser's click is 2.8x larger than Playwright's because every click response embeds the DOM diff (NEW/REMOVED/CHANGED lines). Playwright returns a bare confirmation, forcing the LLM to follow up with a browser_snapshot or browser_evaluate to see what happened. Over a full benchmark run, Playwright MCP spends 47 browser_evaluate calls averaging 2,155 chars against Public Browser's 33 at 510 chars. Public Browser delivers the diff inline. Net result: PB's click+read_page+evaluate total is 120k chars vs Playwright MCP's 170k — 30% less response content overall.
view_pageis 5.4x more compact than Playwright MCP'sbrowser_snapshot
Measured on the 35-test benchmark (2026-04-09): Public Browser's view_page averages 1,124 chars per call vs Playwright MCP's browser_snapshot at 6,084 chars. Same page, same test suite, same LLM driver. The a11y-tree compression + Ambient Context pipeline means we only send what the agent actually needs — smaller responses, less context pressure, cheaper runs.
See test-hardest/BENCHMARK-PROTOCOL.md for the full protocol, per-test breakdown, and raw JSON runs with tool_efficiency blocks.
Cortex — Self-Learning Pattern Engine
Public Browser includes a lightweight learning layer called Cortex. It observes which tool sequences work on different page types and feeds that knowledge back as hints to the LLM agent. No ML model, no training step — just deterministic pattern recording and Markov-chain predictions.
How it works
Page Classification — Every page is classified by its accessibility tree into one of 16 functional types:
login,signup,mfa,search_form,search_results,data_table,form_simple,form_wizard,article,navigation,dashboard,settings,media,checkout,profile,error. The classifier is rule-based (ARIA roles, landmarks, keyword signals) — no domains or URLs are involved.Pattern Recording — Successful tool-call sequences (e.g.
navigate → view_page → fill_form → clickon aloginpage) are recorded into a local append-only Merkle log (~/.public-browser/patterns.jsonl). Only page type, tool names, a content hash, and a timestamp are stored — no URLs, no page content, no PII.Markov Predictions — Recorded patterns are ingested into a first-order Markov table that models
P(next_tool | last_tool, page_type). When the agent lands on a page, the Cortex returns the most likely next tools with probabilities. Stale entries decay automatically (0.95/week, removed after 30 days).Community Markov Table — A hand-curated transition table (
community-markov.json) ships with every installation. It contains baseline probabilities for common page types so that new installations benefit from community knowledge immediately, without needing local history. The table is SHA-256 verified at load time and merged with local patterns (local data takes precedence).
Privacy by design
The Cortex stores and transmits only structural metadata — page types (not domains), tool names (not arguments), and content hashes (not content). A login pattern reveals nothing about which login page was visited. The telemetry payload is built via explicit field allowlist (no spread operator), preventing accidental leakage of future fields.
Opt-in telemetry
Telemetry is disabled by default. To contribute your anonymised patterns back to the community table, set PUBLIC_BROWSER_TELEMETRY=1. Uploads go via HTTPS only; non-HTTPS endpoints are rejected. Each pattern is rate-limited to prevent duplicate uploads.
Local friction log (developer opt-in)
For development of Public Browser itself there is a second, fully local opt-in: SILBERCUE_CHROME_FRICTION_LOG=1 makes the server count tool calls, tool errors and detected fallback spirals per run in ~/.silbercue-chrome/friction-queue.json. It records counters, timestamps and the working directory — never page content, URLs or user input — and nothing ever leaves the machine. Without the variable the code path is not entered at all: no file, no counters, no hints.
Architecture
Public Browser (Node.js MCP server, public-browser)
+-- @modelcontextprotocol/sdk (stdio transport)
+-- CDP Client
| +-- WebSocket transport (existing Chrome on :9222)
| +-- Pipe transport (auto-launched Chrome with --remote-debugging-pipe)
+-- Auto-Launch: Chrome + optimal flags, visible by default
+-- A11y-tree cache + Selector cache
+-- Session Manager (OOPIF support for iframes and Shadow DOM)
+-- Tab State Cache (URL/title/ready across tabs)
+-- Cortex (self-learning pattern engine)
| +-- Page Classifier (16 page types from a11y-tree)
| +-- Pattern Recorder + Merkle Log (local persistence)
| +-- Markov Table (transition predictions)
| +-- Community Table (shipped baseline, SHA-256 verified)
| +-- Hint Matcher (delivers predictions to tool responses)
| +-- Telemetry Upload (opt-in, HTTPS, rate-limited)
+-- Script API (Python, source install from ./python)
| +-- Shared Core via HTTP (:9223) — same tool handlers as MCP
| +-- Escape Hatch via WebSocket (:9222) — direct CDP for power users
+-- 25 tools
Reading - Interaction - Navigation - Scripting - ObservationConnection priority:
Auto-Launch (default, zero-config) — starts Chrome as a child process via
--remote-debugging-pipe, visible as a window, with all flags set for reliable screenshots and keyboard focus.WebSocket (optional) — if you already run Chrome with
--remote-debugging-port=9222, Public Browser connects to that instead. Use this to control your own browser with its extensions and login sessions.
Requirements
Node.js >= 18
Google Chrome, Chromium, or any Chromium-based browser (auto-detected on macOS/Linux/Windows; override with
CHROME_PATH)
Environment Variables
Variable | Values | Default | Description |
|
|
| Auto-launch Chrome if no running instance found |
|
|
| Opt-in headless mode for CI/server environments |
|
|
| CDP debugging port. Non-default values spawn an isolated Chrome instance (separate |
| host |
| CDP host. Alias: |
|
|
| Script API port (needs |
|
|
|
|
| path | — (temp dir) | Directory downloads are written to. Created if missing, never deleted |
|
| — (off) | Report a |
|
|
|
|
| path |
| Per-instance cortex pattern store |
| path | — | Chrome user profile directory (auto-launch only). Alias: |
| path | — | Path to Chrome binary (overrides auto-detection) |
|
| — (disabled) | Opt-in: upload anonymised Cortex patterns to the community endpoint |
| URL |
| Override the telemetry collection endpoint (must be HTTPS) |
Invalid values fail loudly: an unparseable port or naming mode aborts startup
with a named error instead of silently falling back to 9222. Sessions created
through the Node library ignore every variable in this table except
CHROME_PATH and the telemetry pair — see Node Library API.
License
MIT licensed — see LICENSE. Use it however you want, commercially or otherwise.
Contributing
Issues and pull requests welcome at github.com/Silbercue/public-browser.
Privacy
Public Browser runs entirely on your machine. All browser automation happens locally via CDP. The Cortex learning layer stores only structural metadata locally (page types, tool names, content hashes — no URLs, no domains, no page content, no PII). Telemetry is off by default. If you opt in via PUBLIC_BROWSER_TELEMETRY=1, only the same structural metadata is uploaded via HTTPS — the payload is built from an explicit field allowlist to prevent accidental leakage.
Links
Available Tools
25 toolsbatch_evaluateA
Visit multiple URLs sequentially and evaluate the same JavaScript expression on each page. Use for controlled batch checks across known pages when view_page/run_plan would be too chatty. Not for normal page reading, clicking, or form work.
| Name | Required | Description | Default |
|---|---|---|---|
| urls | Yes | Array of URLs to visit and evaluate sequentially | |
| settle_ms | No | Wait time in ms after each page load before evaluating (default: 2000) | |
| continue_on_error | No | Continue processing remaining URLs if one fails (default: true) | |
| evaluate_per_page | Yes | JavaScript expression to evaluate on each page after it loads | |
| timeout_per_page_ms | No | Timeout per page in ms for the full navigate+settle+evaluate cycle (default: 30000) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, so description must cover behavior. It mentions sequential execution and batch nature but lacks details on return format, error behavior, or auth needs. Schema covers timeouts and continue_on_error partially. Adequate but not comprehensive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two concise sentences, front-loaded with essential info. No unnecessary words. Every sentence adds value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Describes purpose and usage well, but lacks output schema or explanation of return results. For a batch tool, missing output behavior is a gap. Parameters are well-documented, but overall completeness is moderate.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with good descriptions. The description adds context like 'sequential' and 'controlled batch' beyond schema. Slight extra value beyond baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description clearly states it visits multiple URLs sequentially and evaluates JavaScript expressions. Distinguishes from siblings like view_page/run_plan by noting batch use case.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says when to use (controlled batch checks) and when not to (normal page reading, clicking, form work). Provides alternative tools (view_page, run_plan) for different scenarios.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
capture_imageA
Pixel-level visual screenshot (WebP, max 800px, <100KB). Do NOT call this to see what is on the page — call view_page instead (10-30x cheaper, returns text + refs you can click). capture_image cannot drive click/type and cannot read text. The ONLY valid uses: (1) canvas/chart content that has no DOM text, (2) pixel-level animation or rendering comparison, (3) the user explicitly asks for a screenshot. If you are unsure, use view_page.
| Name | Required | Description | Default |
|---|---|---|---|
| som | No | Overlay numbered labels on interactive elements matching view_page ref IDs (Set-of-Mark) | |
| full_page | No | Capture full scrollable page instead of just viewport |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations present, so description fully carries the burden. Discloses inability to drive click/type or read text, and provides size/format constraints. Clearly communicates what the tool cannot do.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Concise, front-loaded with key factual details. One minor redundancy: 'Do NOT call this to see what is on the page — call view_page instead' could be slightly tighter, but overall no wasted sentences.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Adequate for a simple screenshot tool with no output schema. Provides size limits and use cases. Missing details on return format or error handling, but not critical given its purpose.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema covers 100% of parameters with descriptions. Description adds no further semantics to parameters (full_page, som). Baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb ('capture') + resource ('image') with technical details (WebP, max 800px, <100KB). Distinctly contrasts with sibling 'view_page' by stating its limitations.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly warns against using for general page visibility, recommends 'view_page' as cheaper alternative (10-30x). Lists three narrow valid use cases and advises 'use view_page' when unsure.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
clickA
Click an element by ref, CSS selector, or viewport coordinates. Dispatches real CDP mouse events (mouseMoved/mousePressed/mouseReleased). For canvas or pixel-precise targets, use x+y coordinates instead of ref. If the click opens a new tab, the response reports it automatically. The response already includes the DOM diff (NEW/REMOVED/CHANGED lines) — inspect those changes for success/failure signals instead of following up with evaluate to re-check state. If click fails with a stale-ref error, call view_page for fresh refs and retry. Avoid evaluate(querySelector + .click()) as default recovery — it bypasses the CDP pointer chain and hides real bugs. (Legitimate exception: explicitly testing synthetic JS event plumbing.)
| Name | Required | Description | Default |
|---|---|---|---|
| x | No | X coordinate (viewport pixels) — for canvas or pixel-precise clicks. Use with y instead of ref/selector. | |
| y | No | Y coordinate (viewport pixels) — for canvas or pixel-precise clicks. Use with x instead of ref/selector. | |
| ref | No | A11y-Tree element ref (e.g. 'e5') — preferred over selector | |
| text | No | Visible text to match (e.g. 'Submit'). Finds element by name in the A11y tree — no prior view_page needed. Prefers interactive elements (buttons, links). | |
| selector | No | CSS selector (e.g. '#submit-btn') — fallback when ref is not available | |
| wait_for_diff | No | When true, wait for the DOM diff synchronously before returning (slower but diff is in this response). Default: false — diff piggybacks on the next tool response. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Discloses that it dispatches real CDP mouse events, reports new tabs automatically, includes DOM diff in response, and explains error recovery. No annotations so description carries full burden, and it does so thoroughly.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Concise yet comprehensive; every sentence adds value. Front-loaded with main purpose, then behavioral details, then recovery guidance. No redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers all aspects: parameters, usage modes, response contents (DOM diff, new tab detection), error recovery, and anti-patterns. Complete for a click tool with no output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Each parameter has a clear description in the schema (100% coverage), and the description adds extra context: ref vs selector priority, text targeting without view_page, x+y for canvas, and wait_for_diff behavior.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly states the action (click) and resources (element by ref, CSS selector, or coordinates). Distinguishes from siblings by specifying use cases for different target types.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit guidance: use coordinates for canvas, recover from stale ref by calling view_page, avoid using evaluate click as default recovery. Also highlights when to use text-based targeting without prior view_page.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
configure_sessionA
View/set session defaults for recurring parameters (tab, timeout, etc.). Without params: show current defaults and auto-promote suggestions. With autoPromote: true: apply all suggestions. Use profile param BEFORE any browser interaction to launch Chrome with a named profile.
| Name | Required | Description | Default |
|---|---|---|---|
| profile | No | Chrome profile name (e.g. "Julian", "Business"). Use `public-browser profiles` to list available profiles. With restart: true, can switch profiles mid-session. | |
| defaults | No | Set session defaults. Keys: param names (tab, timeout, etc.). Values: default values. null removes a default. | |
| autoPromote | No | If true, apply all current auto-promote suggestions as defaults |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses that the tool can view/set defaults and apply auto-promote suggestions, and that using profile launches Chrome with a named profile. However, it does not detail side effects, persistence, or safety aspects (e.g., whether changes affect ongoing interactions).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three concise sentences. The first covers the overall purpose, the second explains the two operational modes, and the third provides a critical usage instruction. No redundant information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given 3 parameters, no output schema, and no annotations, the description explains the main functionality and modes. It notes that viewing returns current defaults and suggestions, but does not specify the return format or how changes affect subsequent session actions. Overall, it is fairly complete but has minor gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, with each parameter described. The description adds extra value beyond the schema by specifying the timing for the profile parameter ('BEFORE any browser interaction'). This enhances the semantic understanding beyond the schema's description.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool can view or set session defaults for recurring parameters like tab and timeout. It distinguishes between viewing current defaults and applying auto-promote suggestions. This is distinct from sibling tools which are mostly browser interaction or evaluation tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear context for when to use the tool: to view or set defaults, and with the autoPromote parameter to apply suggestions. It also gives a crucial usage tip for the profile parameter (use before browser interaction). However, it does not explicitly state when not to use it or mention alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
console_logsA
Retrieve collected browser console logs. Filter by level (info/warning/error/debug) and/or regex pattern. Optionally clear the buffer after reading.
| Name | Required | Description | Default |
|---|---|---|---|
| clear | No | Clear the log buffer after returning results | |
| level | No | Filter by log level | |
| pattern | No | Regex pattern to match against log text |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the burden. It mentions the optional clear buffer action (a behavioral trait), but does not disclose other behaviors such as performance impact, rate limits, or what happens to logs after reading. Adequate but not comprehensive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences long, front-loading the main purpose and then listing parameters concisely. No wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the lack of an output schema, the description should explain what the tool returns (e.g., an array of log objects with message, level, timestamp). It does not, which is a gap. Additionally, it does not relate to siblings like batched actions or session management.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3. The description adds clarity by specifying the enum values for level (info/warning/error/debug), explaining pattern as regex matching, and noting that clear is optional. This adds value beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states that this tool retrieves browser console logs and provides specific filtering options (level, regex) and an optional clear action. It is distinct from sibling tools like network_monitor or observe.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use (when you need to retrieve console logs) and what parameters are available, but does not explicitly state when not to use or compare to alternatives. It provides sufficient context for typical use.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
dom_snapshotA
Structured layout data: bounding boxes, computed styles, paint order, colors. Refs match view_page. Use ONLY for spatial questions view_page cannot answer (is A above B? what color?). For element discovery or text: use view_page. For pure visual verification: use capture_image.
| Name | Required | Description | Default |
|---|---|---|---|
| ref | No | Element ref (e.g. 'e42') to get subtree snapshot for |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description effectively conveys the tool's read-only nature and output contents. It could mention error handling (e.g., if ref is invalid), but the core behavioral traits are clear.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with no redundant words. First sentence states output, second gives precise usage guidance—maximally efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple tool with one parameter and no output schema, the description covers purpose, output types, and usage boundaries. It doesn't detail subtree depth or error responses, but the context is sufficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The single parameter 'ref' is explained in schema; description adds value by linking ref to view_page's refs, aiding cross-tool consistency. Schema coverage is 100%, elevating baseline from 3 to a 4.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly states it provides structured layout data (bounding boxes, computed styles, paint order, colors) and distinguishes from siblings view_page and capture_image, making the purpose explicit and unique.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Openly states when to use ('spatial questions view_page cannot answer') and when not to ('for element discovery or text: use view_page; for visual verification: use capture_image'), providing explicit alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
downloadA
Check status of file downloads or list all downloaded files in this session. Downloads happen automatically when you click download links or navigate to files (PDFs, CSVs, etc.) — you do NOT need to call this tool to trigger downloads. Use this tool to:
Wait for a large download to finish: download()
List all downloaded files, without waiting: download({ action: "list" })
| Name | Required | Description | Default |
|---|---|---|---|
| action | No | status: check/wait for pending downloads (waits briefly for one to start, then until it finishes). list: full session history, returns immediately and never waits — use it for polling loops. | status |
| settle | No | Grace window in ms to wait for a download to START before reporting 'no downloads' (default: 250). Chrome fires downloadWillBegin a few ms after the click that triggers it. Set 0 for an instant check, or use action: 'list' which never waits. | |
| timeout | No | Max wait time in ms for pending downloads (default: 30000) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the behavioral burden. It discloses that downloads happen automatically, that the tool waits for downloads (status) or returns immediately (list), and that it does not trigger downloads—preventing a common misuse. It does not describe the return format or side effects, but for a simple read-only check tool, the essential behaviors are covered.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and front-loaded with the core purpose. It uses a clean structure: a first sentence stating the function, a key clarification about not triggering downloads, and bulleted usage examples. While it could be slightly tighter (the second sentence could be merged), it is well-organized and each sentence contributes meaning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with 3 optional parameters, no required params, no output schema, and no annotations, the description provides sufficient context. It covers the main use cases, explicitly mentions the session scope, explains the waiting behavior, and distinguishes between status and list actions. Nothing an agent needs to call it correctly is missing; the only minor gap is lack of a description of the return value format.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already describes all three parameters with 100% coverage, so the baseline is 3. The description adds value by demonstrating usage patterns: the default download() call and the download({ action: "list" }) call, and by clarifying the behavior of the 'action' parameter beyond the enum values (e.g., list never waits). This goes slightly beyond the schema's descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a precise statement: 'Check status of file downloads or list all downloaded files in this session.' This identifies a specific verb (check/list) and resource (downloads) and immediately clarifies the scope. It also distinguishes itself by stating it does NOT trigger downloads, which sets it apart from any potential sibling that might initiate downloads. This is clear and unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly tells the agent when NOT to use it ('you do NOT need to call this tool to trigger downloads') and when to use it: waiting for a large download or listing downloaded files. It provides concrete call patterns (download() and download({ action: "list" })) and even hints at polling use with 'list' returning immediately. This fully equips the agent to decide when to invoke it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
dragA
Drag an element via native CDP mouse events (mousePressed → interpolated mouseMoved with buttons:1 → mouseReleased). Works for CSS-driven drag: slider thumbs, resize handles, text selection, mouse-based reorder lists (e.g. SortableJS in mouse mode). NOT suitable for HTML5 Drag&Drop API (draggable=true elements with dragstart/drop listeners, React DnD HTML5Backend, Vuedraggable, ng2-dnd) — that path needs Input.dispatchDragEvent which this tool does not implement. Parameters: from_ref/from_selector OR from_x+from_y as source, to_ref/to_selector OR to_x+to_y as target. steps (default 10, min 5) controls mouseMoved granularity.
| Name | Required | Description | Default |
|---|---|---|---|
| to_x | No | Target X coord (viewport px) | |
| to_y | No | Target Y coord (viewport px) | |
| steps | No | Anzahl mouseMoved-Events zwischen press und release (min 5 fuer HTML5-dragover) | |
| from_x | No | Source X coord (viewport px) — alternative zu Ref | |
| from_y | No | Source Y coord (viewport px) — alternative zu Ref | |
| to_ref | No | A11y-Tree target ref (e.g. 'e7') | |
| from_ref | No | A11y-Tree source ref (e.g. 'e5') | |
| to_selector | No | CSS selector for target element | |
| from_selector | No | CSS selector for source element |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Discloses the exact event sequence (mousePressed → interpolated mouseMoved → mouseReleased) and parameter group constraints (from_ref/from_selector OR from_x+from_y). No annotations exist, so description carries full burden, and it does so well.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Description is front-loaded with mechanism and use cases; each sentence adds information. Slightly dense but not overly verbose. Could be slightly more structured, but overall efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For 9 parameters, no output schema, and no annotations, the description is quite thorough. Explains event mechanism, parameter groups, and limitations. Minor gap: no mention of return value or error handling.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema covers 100% of parameters, but description adds value by explaining the two coordinate/selector groups and clarifying the 'steps' default and minimum. This context helps understanding beyond schema types.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses specific verbs ('Drag', 'mouse events') and lists concrete use cases (slider thumbs, resize handles, text selection), clearly distinguishing from HTML5 Drag&Drop API. It leaves no ambiguity about the tool's function.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
States when to use (CSS-driven drag) and explicitly when NOT to use (HTML5 Drag&Drop). Could mention alternative tool for HTML5 Drag&Drop, but the exclusion is clear and helpful.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
evaluateA
Execute JavaScript in the browser page context. Good uses: computation, style mutations (.style.X = ..., classList.add), shadow-root traversal, in-page fetch(), app-specific side effects no dedicated tool covers. Bad uses: (1) automatic recovery after a click/type/fill_form failure — call view_page for fresh refs and retry instead; (2) scrolling — use scroll via run_plan (returns position + content growth); (3) element discovery (querySelector/getElementById/innerText) — prefer view_page or fill_form. Scope is shared between calls — top-level const/let/class are auto-wrapped in IIFE. If/else blocks may return undefined — use ternary (a ? b : c) or explicit return.
| Name | Required | Description | Default |
|---|---|---|---|
| expression | Yes | JavaScript code to execute in the page context | |
| await_promise | No | Whether to await Promise results |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, so description carries full burden. It discloses scope sharing, IIFE wrapping for top-level declarations, and that if/else may return undefined—suggesting ternary or explicit return. This is valuable beyond the input schema, though it could mention sandboxing or security implications.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Description is well-structured with bullet points and clear sections, front-loaded with the main purpose. Every sentence adds value, though it is slightly verbose. Could be more concise without losing clarity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite thorough coverage of usage and behavior, the description omits information about the return value of the executed JavaScript. Since there is no output schema, this is a significant gap for an agent to understand what the tool returns, especially for promise handling.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% (expression and await_promise are fully described in the schema). Description adds minimal additional meaning beyond the schema, primarily discussing execution behavior rather than parameter details. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description clearly states 'Execute JavaScript in the browser page context' with a specific verb and resource. It distinguishes good uses (computation, style mutations, shadow-root traversal) from bad uses with explicit alternatives (view_page, scroll, fill_form), differentiating it from 24 sibling tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly lists good uses, bad uses, and alternatives for each bad case (e.g., automatic recovery after failure → view_page; scrolling → scroll via run_plan; element discovery → view_page or fill_form). Provides clear when-to-use and when-not-to-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
file_uploadA
Upload file(s) to a file input element. Provide ref or CSS selector to identify the , and absolute path(s) to the file(s).
| Name | Required | Description | Default |
|---|---|---|---|
| ref | No | A11y-Tree element ref (e.g. 'e8') — preferred when input is visible in view_page | |
| path | Yes | Absolute file path(s) to upload. String for single file, array for multiple files. | |
| selector | No | CSS selector (e.g. 'input[type=file]') — use this for hidden file inputs (display:none, off-screen). Many React/Vue apps render a visible custom button that triggers a hidden <input type=file>; the hidden input is NOT in the a11y-tree, so ref won't find it. Pass the selector instead. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description alone must convey behavioral traits. It states the upload action and the required file paths, but does not mention whether the file is immediately selected or if form submission is needed. However, the core behavior is clear and no contradictions exist.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences long, each serving a distinct purpose. The first states the main action and required inputs; the second provides guidance on parameter choice. No redundant or irrelevant information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no annotations, no output schema, and a straightforward use case, the description covers the essential behavioral details and parameter usage. It could mention the lack of automatic form submission, but overall it is adequate for an agent to use the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so baseline is 3. The description adds value by explaining the ref vs. selector distinction beyond the schema's descriptions, clarifying when each is appropriate. This elevates the score to 4.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the verb ('Upload'), resource ('file(s) to a file input element'), and the two identification methods (ref or CSS selector). It distinguishes this tool from siblings like 'download' or 'capture_image'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly explains when to use 'ref' (visible input in view_page) vs 'selector' (hidden file inputs, as in many React/Vue apps). This provides clear context and alternatives, making it easy for the agent to choose correctly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
fill_formA
Fill a complete form with one call — the preferred way to submit any form with 2+ fields. Each field needs ref or CSS selector plus value. Supports text inputs, (by value or visible label), checkboxes (boolean), and radio buttons. Use this INSTEAD of multiple type calls or evaluate-setting select.value: one round-trip, partial errors do not abort, each field reports its own status. On per-field errors, call view_page and retry the failing fields — DO NOT escape to evaluate(querySelector) to patch individual fields; it bypasses framework state management (React, Vue) and hides real bugs.
| Name | Required | Description | Default |
|---|---|---|---|
| fields | Yes | Array of fields to fill. Each field needs ref or selector plus value. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries full burden. It discloses key behaviors: partial errors do not abort, each field reports its own status, supports multiple input types, and prefers ref over selector. Could be improved by mentioning what happens after filling (e.g., form submission), but that's not critical for a fill action.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is tight and well-structured: opens with the core purpose, then specifies how to use parameters, lists supported control types, gives usage guidance and error recovery steps. No extraneous words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool that fills forms with one call, the description covers all necessary aspects: input specification, behavior on partial errors, retry strategy, and warnings against using evaluate. Even without output schema, the agent has enough context to use the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% but description adds significant value: explains that each field requires ref or selector plus value, clarifies value types for different controls, and recommends ref as preferred. Also notes minItems constraint implicitly. This goes beyond the schema's descriptive properties.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly states the action ('fill a complete form'), the resource ('form'), and positions itself as the preferred method for forms with 2+ fields. Distinguishes itself from siblings like 'type' and 'evaluate' by explicitly saying to use it instead.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly tells when to use (forms with 2+ fields) and when not to (avoid multiple type calls or evaluate). Provides clear alternative actions for error recovery: call view_page and retry failing fields, and warns against using evaluate directly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
handle_dialogA
Configure browser dialog handling (alerts, confirms, prompts). Pre-configure BEFORE triggering actions that may show dialogs. Replaces evaluate-based workarounds (window.alert = ...) — handle_dialog uses CDP Page.javascriptDialogOpening and works even when the dialog blocks all JS.
| Name | Required | Description | Default |
|---|---|---|---|
| text | No | Text to enter in prompt dialogs (only used with action: accept) | |
| action | Yes | accept: accept the next dialog, dismiss: dismiss/cancel it, get_status: check pending dialogs |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are present, so the description carries the full burden. It explains that the tool uses CDP Page.javascriptDialogOpening and works even when dialog blocks JS, providing good behavioral context for a setup tool. No contradictory information.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is very concise, consisting of three short sentences, each providing essential information: purpose, usage timing, and technical advantage. No unnecessary words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple 2-parameter tool with no output schema, the description covers purpose, prerequisites, and mechanism. It is complete given the tool's simplicity and the richness of the input schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with detailed descriptions for both parameters (action enum with explanations, text usage). The description does not add extra meaning beyond the schema, so baseline score of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'Configure browser dialog handling (alerts, confirms, prompts).' It distinguishes itself from sibling tool 'evaluate' by explicitly stating it replaces evaluate-based workarounds and works even when JS is blocked.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear guidance: 'Pre-configure BEFORE triggering actions that may show dialogs.' It also mentions replacing evaluate-based workarounds, implying when not to use evaluate. However, it does not exhaustively list all alternatives for every scenario.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
network_monitorA
Monitor network requests via CDP. Workflow: start → trigger action → get(pattern: 'api'). Use INSTEAD of evaluate-based fetch interceptors (window.fetch = ..., XMLHttpRequest.prototype.open = ...) — network_monitor captures all requests including those initiated by the page itself.
| Name | Required | Description | Default |
|---|---|---|---|
| action | Yes | start: begin recording, get: retrieve recorded requests, stop: return and clear | |
| filter | No | Filter results — 'failed': only requests with HTTP >= 400 or network errors | |
| pattern | No | Regex pattern to match against request URLs |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided. Description mentions CDP and captures all page-initiated requests. It explains stop action clears data, but does not disclose potential side effects, permissions, or limitations beyond what is stated.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two concise sentences, front-loaded with purpose, efficient use of words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema, but description implies return format of 'get' action. Workflow hints are sufficient for a simple tool. Could mention return structure but not necessary.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema covers all 3 parameters with descriptions. Description adds workflow context and explains the 'stop' action behavior, adding value beyond schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly states the tool monitors network requests via CDP, distinguishing it from evaluate-based interceptors. Verb+resource is specific.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit workflow (start, trigger action, get) and advises using instead of evaluate-based fetch interceptors. Lacks explicit when-not-to-use scenarios but provides clear context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
observeA
Watch an element for changes over time — use this INSTEAD of writing MutationObserver/setInterval/setTimeout code in evaluate. Two modes: (1) collect — watch for 'duration' ms, return all text/attribute changes (e.g. collect 3 values that appear one after another). (2) until — wait for a condition, then optionally click immediately (e.g. click Capture when counter hits 8). Use click_first to trigger the action that causes changes (observer is set up BEFORE the click, so nothing is missed).
| Name | Required | Description | Default |
|---|---|---|---|
| until | No | JS expression evaluated on each change — stops when it returns true. Variable 'el' is the observed element. Example: el.textContent === '8' | |
| collect | No | What to collect: 'text' for textContent changes, 'attributes' for attribute changes, 'all' for both (default: 'text') | text |
| timeout | No | Maximum observation time in ms (default: 10000, max: 25000) | |
| duration | No | Collect all changes for this many ms, then return them. Mutually exclusive with 'until'. Default: 5000 | |
| interval | No | Polling interval in ms for change detection fallback (default: 100) | |
| selector | Yes | CSS selector or element ref (e.g. 'e5') of the element to observe | |
| then_click | No | CSS selector or element ref (e.g. 'e5') to click immediately when 'until' condition is met (for timing-critical actions). Only used with 'until'. | |
| click_first | No | CSS selector or element ref (e.g. 'e5') to click AFTER the observer is set up but BEFORE collection starts. Use to trigger the changes you want to observe (e.g. 'Start Mutations' button). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description fully discloses key behaviors: observer is set up before click_first, duration and until are mutually exclusive, polling interval fallback, and timeout limit. It does not mention any destructive side effects, but that's expected for a read-only watch tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
At ~100 words, the description is efficient and front-loaded with purpose. It could be slightly more structured with bullet points, but it avoids fluff and each sentence adds value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the complexity (8 parameters, important timing/interactions, no output schema), the description covers the major points: modes, mutual exclusions, click_first timing, then_click usage. It lacks explicit return type description but mentions 'return all text/attribute changes'. Overall, it is sufficient for correct usage.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with good descriptions, but the tool description adds significant context: explains the two modes (collect/until), provides examples of use cases, and clarifies parameter interactions (e.g., then_click only works with until). This adds value beyond the schema alone.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool watches an element for changes, explicitly distinguishing it from writing custom MutationObserver/setInterval code in evaluate. It defines two modes and uses specific verbs like 'watch', 'collect', and 'wait for'. This differentiates it from sibling tools like evaluate and wait_for.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description tells when to use this tool (instead of writing observe logic in evaluate) and explains the two modes. However, it does not explicitly mention when not to use it or compare to other observation tools like wait_for, leaving some ambiguity.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
press_keyA
Press a keyboard key or shortcut. Optionally focus an element first via ref/selector. Use for Enter, Escape, Tab, arrows, shortcuts (Ctrl+K).
| Name | Required | Description | Default |
|---|---|---|---|
| key | Yes | Key to press — e.g. 'Enter', 'Escape', 'Tab', 'a', 'ArrowDown', 'F1'. For printable characters use the character itself. | |
| ref | No | Element ref to focus before pressing key (e.g. 'e5') | |
| selector | No | CSS selector to focus before pressing key (e.g. '#search-input') | |
| modifiers | No | Modifier keys to hold during key press (e.g. ['ctrl', 'shift'] for Ctrl+Shift+key) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It reveals an important behavior: it can optionally focus an element via ref or selector before pressing the key. This is clear and sufficient for a simple keyboard press tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is extremely concise: two sentences covering the action, optional focus, and typical uses. Every word contributes meaning, with no fluff or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity and lack of output schema, the description covers all necessary aspects: the key press action, optional focusing, and example keys/shortcuts. It could mention that pressing a key may trigger page events, but overall it is adequate.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema has 100% description coverage with detailed explanations for each parameter. The description adds only the phrase about optional focus, which is already present in the schema for 'ref' and 'selector'. Thus, it provides minimal additional value over the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action (press a key) and the resource (keyboard). It distinguishes from siblings like 'click' and 'type' by specifying keys, shortcuts, and optional element focus. Examples like 'Enter', 'Escape', and 'Ctrl+K' make the purpose immediately understandable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives specific use cases ('Enter, Escape, Tab, arrows, shortcuts (Ctrl+K)'), which guides the agent on when to use this tool. It implies the tool is for individual key presses or shortcuts, not for typing text (use 'type') or clicking (use 'click'), but does not explicitly state exclusions or alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
run_planA
Execute a sequential plan of tool steps server-side. Supports variables ($varName), conditions (if), saveAs, error strategies (abort/continue/capture_image), suspend/resume. Parallel tab execution via parallel: [{ tab, steps }].
| Name | Required | Description | Default |
|---|---|---|---|
| steps | No | Array of tool steps to execute sequentially. | |
| resume | No | Resume a previously suspended plan. | |
| parallel | No | Array of tab groups to execute in parallel across tabs. | |
| use_operator | No | Operator mode (rule engine + Micro-LLM). Requires the executeOperator hook to be registered. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full burden. It mentions features like variables, conditions, error strategies, and suspend/resume but lacks details on execution order, side effects, or error handling specifics beyond naming abort/continue/capture_image.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two concise sentences front-load the core purpose and enumerate features with no wasted words. Ideal structure for quick understanding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema, and description omits what the tool returns (e.g., plan ID, results). For a complex orchestration tool, this is a significant gap. Also lacks details on error strategies and variable scoping.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema has 100% coverage, so the description adds minimal value beyond high-level feature listing. It groups concepts but doesn't elaborate on parameter usage beyond what schema already provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it executes a sequential plan of tool steps server-side, listing key features. The name 'run_plan' is self-explanatory, and it distinguishes itself from single-step sibling tools like click, type, etc.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage for multi-step orchestration versus single-step siblings but does not explicitly state when not to use or provide alternative tools for simpler tasks.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
scrollA
Scroll the page, a container, or an element into view. Returns position and content-growth tracking (scrollHeight grew by Npx — useful for detecting lazy-loaded content). Do NOT scroll with evaluate(window.scrollTo/scrollBy) — scroll handles position tracking and settle timing automatically. Use container_ref/container_selector + direction to scroll inside a specific container.
| Name | Required | Description | Default |
|---|---|---|---|
| ref | No | Element ref to scroll into view (e.g. 'e42') | |
| amount | No | Pixels to scroll (default: 500). Only used with direction. | |
| selector | No | CSS selector to scroll into view (e.g. '#item-30') | |
| direction | No | Scroll direction (when no ref/selector given). Default: down | |
| container_ref | No | Scrollable container ref — scroll this container instead of the page (e.g. 'e10') | |
| container_selector | No | Scrollable container CSS selector (e.g. '.sidebar-list') |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It discloses that the tool returns position and content-growth tracking, and that it handles settle timing automatically. It does not mention potential side effects or error conditions, but the key behaviors are transparent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences with a critical warning, front-loaded with the core action. Every sentence adds value: what it does, return info, warning, usage pattern. No redundancy or fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the 6 parameters, no output schema, and no annotations, the description covers the core behavior, return values, and parameter relationships reasonably well. It could mention error handling or edge cases, but it is sufficiently complete for most use cases.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so baseline is 3. The description adds meaning by explaining the relationship between ref/selector and container/direction/amount, noting defaults (direction: down, amount: 500), and clarifying that amount is only used with direction.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool scrolls the page, a container, or an element into view, using specific verbs and resources. It distinguishes itself from sibling tools like evaluate by explicitly warning against using window.scrollTo/scrollBy and explaining the automatic position tracking and settle timing.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit guidance on when to use container_ref/container_selector with direction for scrolling inside a container, and advises against using evaluate for scrolling. However, it does not fully cover all alternative scenarios or prerequisites for each parameter combination.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_page_dataA
Write a large payload (>1 MB) to window.__pb_data[key] in the page, bypassing the CDP 1 MB-per-message limit via server-side chunking. Use when: passing big base64 images / JSON / fixtures to a debug hook (window.__yourHook(data)), stubbing fetch responses with large bodies, or feeding binary data to a custom drop-zone. Sources: inline (pass data directly — useful for known small payloads) or file (pass absolute path, server reads as binary). After this call the page can read window.__pb_data[''] (string OR ArrayBuffer depending on encoding) and window.__pb_data['__complete'] === true once all chunks landed. Note: each call chunks sequentially over the CDP WebSocket — do NOT issue multiple set_page_data calls for the same key in parallel; concurrent writes would race on window.__pb_data[key]. Do NOT use for: small (<200 KB) payloads where a single evaluate works, or where file_upload with an would suffice.
| Name | Required | Description | Default |
|---|---|---|---|
| key | Yes | Property name under window.__pb_data (JS identifier — letters, digits, underscore; cannot start with digit) | |
| source | Yes | Where to read the payload from. type 'inline' → pass `data` as a string. type 'file' → pass absolute `path`; the server reads the file as binary. | |
| encoding | No | Encoding interpretation. 'utf8' (default for inline) keeps the data as a string. 'binary' (default for file) decodes to ArrayBuffer in the page so apps can pass it to FileReader / Blob / fetch body. 'base64' keeps the base64 string as-is (the page can decode it itself). | |
| chunkSize | No | Raw bytes per chunk before base64 encoding. Default 500_000 (~670 KB base64, safe under CDP's 1 MB-per-message limit). Capped at 700_000 (~933 KB base64) to leave safety margin. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Given no annotations, the description fully discloses chunking, CDP sequential order, race condition, encoding defaults, chunkSize cap, and post-call state (__complete flag).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Description is lengthy but every sentence provides value; front-loaded with purpose and constraints. Minor redundancy could be tightened.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers all aspects: purpose, usage, parameters, behavior, and post-call state without output schema. Complete for a complex chunking tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, but description adds context for each parameter: encoding defaults, chunkSize limit, source options meaning, and key format constraints.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it writes a large payload (>1 MB) to window.__pb_data[key] via server-side chunking, distinguishing it from siblings like evaluate and file_upload.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly provides 'Use when' scenarios (big base64 images, stubbing fetch responses, feeding binary data) and 'Do NOT use for' situations (small payloads, file_upload), plus concurrency warning.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
switch_tabA
Open a new tab, switch to an existing tab by ID (from virtual_desk), or close a tab. Prefer 'open' over navigate when you don't want to touch the user's active tab. After switching, refs from the previous tab are invalid — call view_page FIRST to get fresh refs before click/type/fill_form. DO NOT try to reuse old refs via evaluate(querySelector) as a shortcut.
| Name | Required | Description | Default |
|---|---|---|---|
| tab | No | Tab ID or tab number (1-based index, e.g. '2') to switch to or close (defaults to active tab for close) | |
| url | No | URL to navigate to (for open action, defaults to about:blank) | |
| action | No | Action: open (new tab), switch (to existing tab, default), close (close tab) | switch |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description must bear the full burden. It discloses that refs become invalid after switching and advises against using evaluate as a shortcut. However, it does not mention potential side effects like closing a tab's resources or authentication requirements.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise (two sentences plus a warning), front-loaded with purpose, then usage guidelines, then important behavioral notes. No redundant information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema and moderate complexity, the description covers purpose, usage, and cross-tab behavior. It mentions sibling tool 'navigate' for differentiation. It does not explicitly state the default for close action (active tab), though the schema does.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already covers all parameters with descriptions (100% coverage). The description adds useful context: tab IDs come from virtual_desk, and actions have defaults. This adds value beyond the schema but does not introduce new parameter details.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the three actions (open, switch, close) and the specific resource (tabs). It distinguishes from the sibling tool 'navigate' by advising preference for 'open' when not wanting to affect the user's active tab.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit when-to-use guidance: prefer 'open' over 'navigate' to avoid touching the active tab. It also instructs to call view_page after switching to get fresh refs, and warns against reusing old refs via evaluate.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
tab_statusA
Active tab's cached URL/title/ready/errors for quick sanity checks mid-workflow ('did my click navigate?'). For tab discovery: use virtual_desk. For page content: use view_page.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, so description carries full burden. It discloses that data is 'cached' and lists specific fields (URL, title, ready, errors). This implies read-only behavior and provides key behavioral context beyond the empty schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences only. First sentence defines purpose and outputs. Second sentence provides sibling differentiation. No wasted words; front-loaded with key information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema, but description explains return values (URL, title, ready, errors). Covers essential aspects for a zero-parameter tool: what it returns, when to use, and alternative tools. Highly complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
No parameters exist (schema coverage 100%). Baseline score 4 applies; description adds no parameter info, which is appropriate given zero parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description clearly states it provides cached URL, title, ready status, and errors for sanity checks. Uses specific verb-resource combination and distinguishes from siblings by referencing virtual_desk and view_page.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly tells when to use (mid-workflow sanity checks like 'did my click navigate?') and when not to use (tab discovery via virtual_desk, page content via view_page).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
typeA
Type text into an input field identified by ref or CSS selector. For multiple fields in the same form, prefer fill_form — it handles text inputs, , checkbox, and radio in one round-trip and is more reliable than N separate type calls. For special keys (Enter, Escape, Tab, arrows) or shortcuts (Ctrl+K), use press_key instead. On stale-ref errors, call view_page for fresh refs and retry. Avoid evaluate(element.value = ...) as default data-entry recovery — it bypasses framework listeners (React, Vue) and masks real failures. (Legitimate exception: tests explicitly targeting synthetic event plumbing.)
| Name | Required | Description | Default |
|---|---|---|---|
| ref | No | Element reference from view_page (e.g. 'e12') — preferred over selector | |
| text | Yes | Text to type into the element | |
| clear | No | Clear existing field content before typing (default: false) | |
| selector | No | CSS selector as fallback (e.g. 'input[name=email]') |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden. It discloses that the tool types text, can clear fields, uses ref or selector, and handles stale-ref errors. It warns about bypassing framework listeners if using evaluate, which is a behavioral trait. However, it does not mention any permissions, rate limits, or confirm whether the action is destructive (though typing is generally non-destructive).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is packed with information but remains efficient at 4 sentences. It is front-loaded with the core purpose, then expands with usage guidelines and error recovery. While slightly long, every sentence earns its place, making it useful without being overly verbose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's moderate complexity (4 params, none nested, no output schema), the description covers the main aspects: behavior, parameter usage, alternatives, and error handling. It lacks explicit mention of return values, but that is somewhat inferable. The guidance on stale-ref and evaluate are valuable additions that enhance completeness.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Since schema coverage is 100%, baseline is 3. The description adds value by explaining the relationship between ref and selector ('preferred over selector') and the clear parameter's purpose. It clarifies that ref is from view_page and selector is a CSS fallback, which goes beyond the schema's minimal descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states what the tool does: 'Type text into an input field identified by ref or CSS selector.' It distinguishes from siblings like fill_form and press_key by specifying when to prefer them, making the purpose and differentiation explicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit guidance on when to use this tool versus alternatives: 'For multiple fields in the same form, prefer fill_form' and 'For special keys... use press_key instead.' It also includes error recovery instructions for stale-ref errors and warns against using evaluate as a default, covering when-not-to-use scenarios comprehensively.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
view_pageA
The way to see what is on the page. Call this after navigate/click/switch_tab — not capture_image. Returns text content + stable element refs (e.g. 'e5') for click/type/fill_form. Also use this to read visible text, check errors, find buttons. Default filter:'interactive' shows actionable elements; for paragraphs/table cells call view_page(ref: 'eN', filter: 'all'). Collapsed containers show as [eXX role, N items] — expand with view_page(ref:'eXX', filter:'all'). 10-30x cheaper than capture_image.
| Name | Required | Description | Default |
|---|---|---|---|
| ref | No | Element ref (e.g. 'e5') to get subtree for | |
| depth | No | Nesting depth — how many tree levels to display (default: 3). Controls indentation, not visibility. Hidden sections (display: none) require clicking tabs/buttons to reveal. | |
| filter | No | Filter mode: interactive (default), all, landmark, or visual (adds bounds/click/visibility) | interactive |
| max_tokens | No | Token budget — page content is automatically downsampled to fit. Omit for full output. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description fully discloses behavior: returns text and element refs, cost comparison to capture_image (10-30x cheaper), collapsed container display format, depth controlling indentation not visibility, and automatic downsampling based on max_tokens.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single paragraph that is well-structured and front-loaded. Every sentence provides value. It is slightly long but necessary given the complexity of parameters and usage scenarios.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the four optional parameters, no output schema, and multiple sibling tools, the description is remarkably complete. It explains return type, usage contexts, filter differences, cost, and expansion of collapsed containers. No gaps identified.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Although schema coverage is 100%, the description adds significant context beyond the schema: depth controls indentation not visibility, filter modes explained, ref for subtree, and max_tokens for downsampling. This helps the agent use parameters correctly.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'The way to see what is on the page.' It specifies when to use it (after navigate/click/switch_tab, not capture_image) and what it returns (text content + stable element refs). It effectively distinguishes from sibling tools like capture_image, click, and navigate.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit guidance on when to call the tool (after navigation actions, not capture_image) and how to use different filters ('interactive' for actionable elements, 'all' for paragraphs/table cells). Also explains expanding collapsed containers and mentions cost efficiency.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
virtual_deskA
PRIMARY orientation tool — call first in every new session, after reconnect, or when unsure. Lists all tabs with IDs, URLs, state. Use returned IDs to navigate to an existing tab instead of opening duplicates. Cheap, call liberally.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description adds behavioral context: it is 'Cheap, call liberally' implying low cost and safe to call frequently. It implies a read-only listing operation without stating it explicitly.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Extremely concise: two sentences, front-loaded with purpose, each sentence adds essential value without waste.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given zero parameters and no output schema, the description fully covers purpose, usage timing, and behavior. It is complete for an agent to select and invoke correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
No parameters exist, so the description correctly adds no parameter info beyond the empty schema. Baseline 4 applies as schema coverage is 100%.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it lists all tabs with IDs, URLs, and state, using a specific verb 'Lists'. It distinguishes itself as the 'PRIMARY orientation tool' from siblings by explicitly recommending it be called first.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit guidance provided: 'call first in every new session, after reconnect, or when unsure.' Also advises using returned IDs to avoid opening duplicates, giving clear when-to-use context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
wait_forA
Wait for a condition: element visible, page text present, URL match, network idle, or JS expression true. Prefer condition:'text' over a JS expression for "has the page said X yet". Set assert:true to check once and fail instead of waiting.
| Name | Required | Description | Default |
|---|---|---|---|
| url | No | Substring of the page URL — required when condition is 'url' | |
| text | No | Substring of the page's visible text — required when condition is 'text'. Case-sensitive; matches document.body.innerText, i.e. what a reader sees. | |
| assert | No | Assert instead of wait: check the condition once and fail if it does not hold (default timeout becomes 0). Failures carry _meta.code = 'assertion_failed'. | |
| timeout | No | Maximum wait time in milliseconds (default: 10000, or 0 when assert is true) | |
| selector | No | CSS selector or element ref (e.g. 'e5') — required when condition is 'element' | |
| condition | Yes | What to wait for: element visibility, visible page text, the URL, network idle, or a JS expression returning true | |
| expression | No | JavaScript expression that should evaluate to true — required when condition is 'js' |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Since no annotations are provided, the description carries the full burden of behavioral disclosure. It clearly explains the wait behavior, the effect of assert:true (single check, fail, default timeout becomes 0), the failure code _meta.code = 'assertion_failed', and even notes that text matching is case-sensitive and uses document.body.innerText. This is thorough and leaves little ambiguity for an agent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences long, front-loads the core purpose, and packs in the most important usage notes (condition preference and assert behavior) without filler. Every clause earns its place; it is appropriately sized for a tool with this complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema, the description covers the key operational details: conditions, timeouts, assert failure behavior, and text matching semantics. It doesn't explicitly state what the tool returns on success, but for a wait tool that is typically a boolean or void, and the absence is minor. The description is sufficient for an agent to call it correctly without further clarification.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 100% schema description coverage, the baseline is 3. The description enriches the schema by adding practical guidance: it explains that text is case-sensitive and matches visible innerText, and it recommends condition:'text' over JS expressions for page-text checks. This goes beyond the schema's bare descriptions and adds decision-making value.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Wait for') and resource ('a condition') and enumerates the distinct condition types (element visibility, page text, URL, network idle, JS expression). It is unambiguous and provides enough specificity that an agent can understand the tool's role without needing to inspect siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description offers concrete usage guidance: it recommends preferring condition:'text' over a JS expression for checking page text, and explicitly explains when to use assert:true ('check once and fail instead of waiting'). While it doesn't spell out when to avoid this tool in favor of an alternative, the preference and assert instructions give clear context for choosing among the tool's own modes.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
TDQS
Every tool has a distinct, well-defined purpose. Overlapping tools like view_page vs capture_image are clearly delineated by use cases and cost guidance. Even generic tools like evaluate and set_page_data are scoped to specific legitimate uses, avoiding ambiguity.
All tool names follow a consistent lower_snake_case verb_noun pattern (e.g., virtual_desk, capture_image, network_monitor). Verbs are clear and predictable, with no mixed conventions or vague synonyms.
25 tools is on the higher end, but each tool addresses a distinct browser automation capability (navigation, interaction, monitoring, data injection). The set is comprehensive without being bloated, as most tools have narrow, non-overlapping roles.
The tool surface covers the full browser automation lifecycle: navigation, page inspection, interaction, tab management, waiting, observing, dialogs, file handling, network/console monitoring, downloads, and advanced scripting. No critical gaps are apparent for the stated purpose.
Maintenance
Related MCP Connectors
Browser MCP for logged-in tasks. Uses your Chrome — credentials stay local. Zero-token replay.
Live browser debugging for AI assistants — DOM, console, network via MCP.
A paid remote MCP for AI agent browser DevTools MCP, built to return verdicts, receipts, usage logs,
Hosted real Google Chrome MCP with per-user persistent state. Navigate, click, type, screenshot.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceThe Zero-Setup Local Browser MCP. Enables AI agents to control web browsers via CDP with zero vision tokens and high-speed DOM mapping.17MIT
- AlicenseNot gradedqualityDmaintenanceA token-optimized MCP server that groups Chrome Devtools tools into 8 semantic operations, reducing context window tokens by 69.5% while preserving full functionality.311MIT
- FlicenseBqualityBmaintenanceUltra-fast browser automation server over Chrome DevTools Protocol (CDP), exposed as MCP, enabling AI agents to control a real Chrome browser with low latency and minimal token usage.21
- AlicenseNot gradedqualityAmaintenanceA zero-dependency MCP server that drives a real Chrome browser through a companion extension, enabling AI agents to automate real user sessions with trusted input events, compact accessibility-tree snapshots, and 14 tools for navigation, interaction, scripting, and inspection.7411MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Silbercue/public-browser'
If you have feedback or need assistance with the MCP directory API, please join our Discord server