Skip to main content
Glama
Mehmoodqureshi

MCP Browser Extension

MCP Browser Extension

CI npm license

Website and docs: mcp-browser-extension.com · Quickstart · All 42 tools · Install the extension from the Chrome Web Store

Let Claude use the Chrome you are already logged into. Not a fresh automated browser that greets every site as a stranger — your Chrome, with your sessions, your cookies, your 2FA already done. If you can see a page in your browser, your agent can read it, without logging in again and without pasting credentials anywhere.

Most browser MCP servers launch their own Chromium and hand your agent a signed-out window. MCP Browser Extension does the opposite: an MV3 extension dials into a localhost WebSocket server and drives the browser you already have open, through chrome.scripting/chrome.tabs. Works with Claude Code, Claude Desktop, and any other MCP host.

MCP Browser Extension has two parts: the extension, and a small MCP server you run with npx (npm package and command: mcp-browser-extension). The extension comes from the Chrome Web Store or loaded unpacked.

This build is extension-only. It never launches or attaches a Chromium of its own, so the extension is required, not optional — without it, no tool can run. The CDP flags (--cdp-fallback, --no-cdp-fallback, --cdp-endpoint, --prefer) are still accepted for back-compat but are ignored.

Full design: docs/BLUEPRINT.md — architecture, wire protocol, the complete tool surface, the extension manifest, the security model, and the phased build plan.

Use Claude in your signed-in Chrome

You are already signed in to Gmail, GitHub, your analytics dashboards, the admin panel, the CRM. MCP Browser Extension lets Claude (Claude Code, Claude Desktop, or any other MCP host) work in those same tabs: no re-login, no second 2FA prompt, no password or cookie in a config file. The extension runs inside your normal Chrome, so a page the agent opens is the page you would see.

  • Gmail — read a thread or search results in a tab you already have open.

  • GitHub — go through PRs, issues and settings pages as yourself, private repositories included.

  • Dashboards — pull numbers from analytics, billing or admin screens that have no API, or whose API you never set up.

Other tools drive a signed-in Chrome too (the hangwin/mcp-chrome extension, for one), so the question is what you get on top of the session:

  • A per-domain allowlist, deny-all by default. With no flags the agent can read nothing. --allow-domain mail.google.com --allow-domain github.com opens exactly those hosts (*.example.com covers a domain and its subdomains); every other site is refused before the call reaches the page. Reads are gated, not only clicks, and the extension re-checks the same policy on its side. Mutations, eval, downloads and uploads are separate opt-ins.

  • Password values are never returned, and --redact scrubs tokens, API keys and JWTs out of page reads.

  • An audit trail: every call is logged with the URL, the allow/deny verdict, duration and bytes returned.

  • It stays out of your tab: the agent opens its own tabs in the background and works there, so the page you are on is never navigated, clicked or pulled out of focus. batch reads many of them at once in one call.

  • Several Chrome profiles: load the extension in your work and personal profiles and switch between them with profile_use.

  • auth_check: when a session does expire, the agent gets an [AUTH_REQUIRED] signal instead of a confusing timeout, so it can stop and ask you to sign in again. MCP Browser Extension never holds credentials or signs in for you.

Setup is two pieces: the MCP server (npx, below) and the extension, which you can install from the Chrome Web Store or load from the folder the server unpacks.

Related MCP server: Controlium

Quickstart

Up and running in one paste

Hand this to your AI agent (Claude Code, Cursor, Windsurf, anything MCP) and it installs the server, wires it into the client, and walks you through the two steps that must happen inside Chrome:

Set up MCP Browser Extension on this machine by fetching and following
https://raw.githubusercontent.com/Mehmoodqureshi/mcp-browser-extension/main/SETUP.md
exactly, step by step. Work autonomously and verify each step.

Prefer to read before you run an agent on your machine? SETUP.md is the exact file the agent follows. The manual steps are below.

1. Register the MCP server with your host.

claude mcp add mcp-browser-extension -s user -- \
  npx -y mcp-browser-extension@latest \
  --allow-domain example.com --enable-mutations --persist-token

Everything before -- belongs to Claude Code; everything after it is this server's command and flags. Keep the -- or --allow-domain gets read as a Claude Code option.

-s user registers it for every project on your machine. Use -s local (the default) for just the current project, or -s project to write a .mcp.json your team can commit.

Check it came up with claude mcp list. After upgrading the server, reconnect it with /mcp inside a session — no restart needed.

{
  "mcpServers": {
    "mcp-browser-extension": {
      "command": "npx",
      "args": ["-y", "mcp-browser-extension@latest",
               "--allow-domain", "example.com", "--enable-mutations",
               "--persist-token"]
    }
  }
}

By default everything is deny-all (no domains, no eval, no mutations). Grant exactly what you need with --allow-domain <glob> (repeatable), --enable-mutations, --enable-downloads, --enable-uploads, --unsafe-enable-eval, or --unsafe-all-domains.

--enable-uploads permits upload_file (setting local file(s) on a page's file <input>). It is off by default because sending local files to a page is an exfiltration risk; it is also gated by the destination-domain allowlist. Pair it with --uploads-dir <path> to restrict uploads to files inside that directory (.. traversal is blocked) — strongly recommended for unattended use.

Pair once, never again. Both examples above include --persist-token, which is what makes the pairing survive a restart — drop it if you'd rather have the stricter default described next.

Without --persist-token a fresh token is minted every boot (the secure default), which means re-pairing the extension on each restart. With it, the token is stored 0600 at ~/.mcp-browser-extension/token and reused; the extension's keepalive auto-reconnects with no manual step. MCP_BROWSER_EXTENSION_TOKEN pins the token explicitly (and is never written to disk).

2. Install the extension — required; the server can drive nothing without it.

Install MCP Browser Extension from the Chrome Web Store. One click, no Developer mode, and Chrome keeps it updated for you. This is the way to install it.

3. Click Connect. A fresh install opens the extension's Settings with a Connect button (it is in the toolbar popup too). Click it, allow the one permission Chrome asks for, and you are paired: the server registers a small helper with Chrome every time it starts, and the button asks it for the port and token. Chrome lets only this extension talk to that helper. If the server ever changes its token, the extension fetches the new one by itself. Nothing to copy or paste.

The extension also ships inside the npm package, and every time the server boots it copies it to ~/mcp-browser-extension (%USERPROFILE%\mcp-browser-extension on Windows; MCP_BROWSER_EXTENSION_EXTENSION_DIR moves it). chrome://extensions → enable Developer mode → Load unpacked → pick that folder. It pairs itself from a pairing.json the server writes there, and the server refreshes the files on each boot (never with an older build) so it reloads itself within 30 seconds.

An unpacked copy does not update through Chrome, so its popup suggests the store copy. Fresh unpacked builds carry the store's public key and so have the same id: load one or the store copy in a Chrome profile, not both. Updates preserve the ID of an existing unpacked installation, including older copies without a manifest key; those continue to pair through the bundled pairing.json. Working from a git clone? npm install && npm run build:ext first; extension-dist/ is gitignored. npm run clean clears server build output and keeps extension-dist/, whose manifest and pairing data may belong to an installation already loaded in Chrome.

Where to see the badge: it sits on the extension's icon in Chrome's toolbar, not on the chrome://extensions page. Chrome hides new extensions behind the puzzle-piece button at the right of the address bar, so click that, find MCP Browser Extension, and click the pin next to it once; the icon then stays in the toolbar. Hover it for the status in words.

Badge

Meaning

green dot

paired and connected

yellow dots

connecting

grey circle

not paired yet (no server has run, or no pairing file)

red exclamation mark

token rejected; the server rotated it, re-pairs by itself in a moment

Manual fallback (the helper is turned off with --no-native-host, or Connect reports a problem): run npx -y mcp-browser-extension@latest --print-pairing, open the extension's Settings, and paste the port + token from ~/.mcp-browser-extension/handshake.json.

Extension missing after restarting Chrome

Run the read-only diagnostic to see the actual installation type, missing files, Chrome disable reasons, and any conflicting extension registrations:

npx -y mcp-browser-extension@latest extension doctor

Older unpacked copies could acquire a new ID when an update added the Web Store public key to their manifest. Chrome then retained both IDs for one folder and skipped that folder on its next startup. Updates now preserve existing IDs. For an installation already affected by this exact conflict:

npx -y mcp-browser-extension@latest extension repair
# Review the preview, fully quit Chrome and other Chromium browsers, then:
npx -y mcp-browser-extension@latest extension repair --apply

The repair backs up the original preferences under ~/.mcp-browser-extension/extension-repair-backups/, removes only the confirmed obsolete registration, and preserves the current extension and its saved settings. It refuses to write while a Chromium browser is running. Reopen Chrome afterwards. Use --user-data-dir <directory> for a custom browser data location, or extension doctor --json for a diagnostic report. Reports contain extension paths and registration status, but no browsing history, cookies or pairing tokens.

A Web Store installation with no matching stale-ID conflict is left unchanged. If the diagnostic finds missing files, a disabled Store copy, or no registration, that needs its own diagnosis; this command does not assume the cause or reset the browser profile. When moving from an unpacked copy to the Store version, remove the unpacked copy first, then install from the Store.

Running more than one session

Every MCP host session (each Claude terminal, tab or window) starts its own MCP Browser Extension server, and they all share your Chrome at once. The first one to start owns the bridge port and the extension connections — the hub. Each later session finds the port held by a live MCP Browser Extension server and joins it as a peer: its tool calls are relayed through the hub to the same browsers, so every session keeps working side by side. Nobody is disconnected.

When the hub's session ends, its peers race for the port; one takes it over (with the same token, so the extension re-pairs by itself within a few seconds) and the rest join the new hub. A call that was in flight at that moment fails once with EXTENSION_DISCONNECTED and is retried automatically when it is safe to repeat.

Peers authenticate with the pairing token from the 0600 handshake file, so only your own OS user can join. A server too old to share the port is replaced as before: it is verified to be an MCP Browser Extension server, then stopped. Anything that isn't a verified MCP Browser Extension server is never touched — a port held by some other program is reported, never killed.

Sessions share one browser, so they also share its tabs: two sessions driving the same tab at the same moment will step on each other. Give each session its own tabs (tab_new), or its own Chrome profile (below).

Each session can also drive several browsers at once: load the extension in each Chrome profile and they all pair to the same server, each under its own profile name. Tools act on the active profile — pick it with --profile <name> at startup or the profile_use tool at runtime.

Naming is automatic. Chrome won't tell an extension which profile it runs in, so each install keeps a random id and the server names it: the first browser is default, the next profile-2, then profile-3, and so on. Names are stored in ~/.mcp-browser-extension/profiles.json, so a browser keeps its name across restarts. chrome_status lists every paired browser (with its active tab as a hint), and profile_rename gives one a friendly name (profile-2 → work). To pin a name yourself instead, type it into the extension's Options → Profile; that always wins.

Without --port, each server binds an ephemeral port (no conflict ever), but the port changes every boot — so you'd re-pair the extension each time. Pin --port plus --persist-token for a pair-once setup.

Windows

WSL2 is not required — native Windows works. One config change is, though: on Windows npx is npx.cmd, a batch shim, and MCP hosts spawn the server without a shell, which cannot execute a .cmd. So "command": "npx" fails to start. Wrap it in cmd /c:

{
  "mcpServers": {
    "mcp-browser-extension": {
      "command": "cmd",
      "args": ["/c", "npx", "-y", "mcp-browser-extension@latest",
               "--allow-domain", "example.com", "--enable-mutations",
               "--persist-token"]
    }
  }
}

Or from Claude Code: claude mcp add mcp-browser-extension -- cmd /c npx -y mcp-browser-extension@latest --allow-domain example.com

For normal use, install the extension from the Chrome Web Store as described above, then click Connect. Do not use Load unpacked as part of the normal Windows setup. The unpacked developer build has the same extension ID as the Store build, so loading it can replace the Store installation; Chrome may then disable the non-Store copy. If you are developing mcp-browser-extension, load %USERPROFILE%\mcp-browser-extension in a separate Chrome profile.

The tools cover tabs, navigation, interaction (click/type/press/hover/ scroll/select_option), reads (get_text/get_html/screenshot/eval/wait_for), an accessibility snapshot (interactive elements with stable refs the model can target instead of guessing CSS selectors), session access (get_cookies/storage), helpers (extract_links/read_as_markdown/fill_form/download_file/upload_file), and chrome_status. upload_file sets local file(s) on a file <input> without the OS dialog (requires --enable-uploads).

click/type accept trusted: true for real OS-level input (works on React/Vue controlled inputs); interactions auto-wait for the target to appear.

Use it from anywhere — --tunnel

Drive the Chrome on your computer from claude.ai, the Claude mobile app, ChatGPT, Claude Code on another machine, or an agent running on a server.

brew install cloudflared            # once (Windows: winget install --id Cloudflare.cloudflared)
npx -y mcp-browser-extension@latest --tunnel --allow-domain example.com --enable-mutations

It prints a connector URL like https://<random>.trycloudflare.com/mcp/<key>:

  • claude.ai / Claude mobile: Settings > Connectors > Add custom connector, paste the URL.

  • ChatGPT (web): Plugins > Add > Add custom MCP server. Choose Server URL, paste the complete connector URL (including /mcp/<key>), and choose No authentication. Create and install the personal plugin, then select it with @ in a new chat. Keep the tunnel running.

  • Claude Code elsewhere / agents: use <url>/mcp with Authorization: Bearer <key>; the exact claude mcp add line is printed too.

The key (32 random bytes, kept in ~/.mcp-browser-extension/remote-key) guards every request; a wrong or missing key gets a bare 404. Anyone holding the URL can drive your browser within the allowed sites, so keep it private and keep the allowlist tight. --rotate-remote-key cuts every client off. The quick-tunnel URL changes on each start; --http alone serves on 127.0.0.1:38018 (--http-port) for your own tunnel (ngrok, Tailscale Funnel, a reverse proxy). The server runs until Ctrl-C.

Proxy per Chrome profile — proxy_status

Chrome applies a proxy to a whole profile, never one tab, so keep a Chrome profile per IP: set the proxy on the extension's Settings page in that profile, name the profile there, and switch with profile_use. A dead proxy fails pages rather than falling back to your real IP. proxy_status reports the exit IP and country; the agent cannot change the proxy or read its password.

Driving several tabs at once — batch

batch runs many tool calls in one request — parallel (default) or serial (with optional stopOnError). Each sub-op goes through the same policy gate, rate limit, and error handling as a direct call (no bypass, no nesting). Use it to fan work out across tabs:

// open three product pages (background, so they don't fight for focus)…
{ "name": "batch", "arguments": { "ops": [
  { "tool": "tab_new", "args": { "url": "https://a.example/p" } },
  { "tool": "tab_new", "args": { "url": "https://b.example/p" } },
  { "tool": "tab_new", "args": { "url": "https://c.example/p" } }
]}}

// …then read them all at once (wall-clock ≈ the slowest one, not the sum)
{ "name": "batch", "arguments": { "ops": [
  { "tool": "get_text", "args": { "tabId": "<a tabId>" } },
  { "tool": "get_text", "args": { "tabId": "<b tabId>" } },
  { "tool": "get_text", "args": { "tabId": "<c tabId>" } }
]}}

In parallel mode, tab-scoped ops must pass an explicit tabId — the active-tab default is unsafe under concurrency, so it's rejected rather than silently mis-routed. (tab_new, tabs_list, chrome_status are exempt.)

The agent works in its own tab, not yours. tab_new opens in the background and that tab becomes the agent's tab: calls without a tabId go there. navigate with no tab of its own yet opens one rather than replacing your page, and tab_new only reuses blank tabs it opened itself, never a New Tab page of yours. Before the agent opens anything, reads see your active tab, so "summarize this page" still works; to act on your page, the agent passes its tabId from tabs_list. Pass active: true to bring a tab to the front.

Reaching into iframes and shadow roots

A selector that "should" match but doesn't almost always means the element is somewhere your selector cannot reach: inside an <iframe> (checkout widgets, OAuth consent screens, embedded editors) or inside a web component's shadow root.

Shadow roots are handled for you — every selector and every ref now resolves through open shadow roots, so anything snapshot shows you is something you can click. (It used to show you elements no click could reach: the snapshot walked shadow roots, the actions did not.)

Frames are opt-in, because reaching into one is a decision:

frames_list {}                                  // what frames exist, and their URLs
click { "selector": "#pay", "allFrames": true } // find it in whichever frame has it
get_text { "frameId": 7 }                       // pin one frame

Every frame is authorized against its own URL before anything runs in it, so an allowlisted page embedding a third-party iframe does not become a way to read that third party. Frames whose origin isn't on your allowlist are skipped.

Seeing why a page broke — console_logs, network_log, dialogs

Reading the DOM tells you what a page looks like after it failed, not why. With --enable-observers, an in-page hook records console output, uncaught errors, and fetch/XMLHttpRequest traffic, and intercepts native dialogs:

console_logs { "level": "error" }        // the exception the page swallowed
network_log  { "failedOnly": true }      // the 500 behind the blank screen
dialogs      { "policy": "accept" }      // answer confirm() with true from here on

It is off by default and deliberately so: the hook patches console, fetch, XMLHttpRequest and the dialog functions on every allowlisted page in your real browser. When it's on, it is registered only for the domains on your allowlist, at document_start (so it catches load-time failures), and nothing it records leaves the page until a tool call reads it — through the same gate as any other page read.

Dialog interception is also a fix, not just an observation: alert/confirm/ beforeunload block the renderer, so a click that opened one used to hang every injected script until the command timed out and reported TIMEOUT with nothing to point at. With observers on, the dialog is answered (dismiss by default: confirm → false, prompt → null) and recorded.

What network_log sees: the requests page code makes — fetch and XMLHttpRequest, with method, URL, status and duration — plus Resource Timing entries (scripts, images, styles) when you ask for them. Not the document request, redirects, or headers. That is the cost of not holding a debugger session open on your browser.

Only what changed — snapshot { diff: true }

A snapshot is the most expensive read in the tool surface, and the loop that uses it most (snapshot → click → snapshot) re-sends a page that is mostly identical every time. Ask for the delta instead:

snapshot { "diff": true }                       // added / removed / changed only
click { "selector": "#save", "snapshotAfter": true }   // what the click changed

Nodes are matched across snapshots by role + accessible name, not by ref — refs renumber in document order on every snapshot, so diffing on them would report an unchanged button as removed-and-re-added the moment anything above it appears.

Targeting by role and name

Actions accept a locator instead of a CSS selector, so you don't need a snapshot first just to learn a ref:

click { "role": "button", "name": "Sign in" }
type  { "role": "textbox", "name": "Email", "text": "a@b.com" }

Resolution is server-side and refuses to guess: an ambiguous locator fails with the candidates listed rather than acting on the first one (pass nth to pick).

Did the session expire? — auth_check and failOnAuthWall

Reusing a signed-in Chrome removes the login step, but a session cookie can still expire mid-run. Without a distinct signal the next step fails as SELECTOR_NOT_FOUND or TIMEOUT, and an eval harness scores the run as an agent failure when it was an auth failure. Every snapshot now carries an authWall verdict when the page looks like a sign-in wall, and there is a dedicated probe:

auth_check {}                                   // { authRequired, confidence, signals }
auth_check { "failOnAuthWall": true }           // [AUTH_REQUIRED] error instead
navigate  { "url": "https://app.example.com/dashboard", "failOnAuthWall": true }
snapshot  { "failOnAuthWall": true }

For a harness, set it once instead of per call:

npx -y mcp-browser-extension@latest --allow-domain app.example.com --enable-mutations --fail-on-auth-wall

With the flag on, every step that can move the tab (navigate, click, type, select_option, press, fill_form, back, forward, reload) checks the page it landed on and fails with [AUTH_REQUIRED] if that page is a sign-in wall, and a wait_for that times out on such a page reports [AUTH_REQUIRED] instead of [TIMEOUT]. Each guarded step costs one extra snapshot round-trip; with the flag off the cost is zero. [AUTH_REQUIRED] is where a harness pauses for a human to sign in again in the same Chrome, then retries the step. MCP Browser Extension never re-authenticates on its own: it holds no credentials, by design.

Detection reads only what the snapshot already has: the URL (sign-in routes, identity-provider hosts such as accounts.google.com, login.microsoftonline.com, Okta, Auth0), the title, password fields, and sign-in controls. high confidence needs two independent cues (a password field plus a sign-in button, say); a lone password field or a bare /auth/... URL is medium. A header "Sign in" link on an ordinary page never counts. failOnAuthWall fires only on high, so a harness can bucket [AUTH_REQUIRED] separately from every other failure while a settings page with a "current password" field carries on.

Printing — print_pdf

print_pdf { "landscape": true }

Renders through Chrome's own print pipeline and saves to the task's results/ dir, returning the path and size. The bytes themselves are never returned — a PDF is megabytes of base64 no model can read.

Paying less per turn — --tools

Every MCP server you connect costs context before you ask it anything: the host sends the whole tool catalog to the model on every turn. MCP Browser Extension's 40 tools are 28 KB of JSON Schema, about 7.1k tokens, on each one.

Most runs need a handful of them. --tools advertises only those:

npx -y mcp-browser-extension@latest \
  --allow-domain app.example.com --enable-mutations \
  --tools tabs_list,tab_new,navigate,snapshot,click,type,get_text

That surface is 6.0 KB, ~1.5k tokens — a 78% cut against the full catalog, for a run that was never going to print a PDF or upload a file.

  • Comma-separated and repeatable: --tools navigate,get_text --tools click.

  • A tool left out is hidden from tools/list and refused if called — a batch op naming it fails the same way an unknown tool does. Hiding a tool is a real restriction, not a display filter. It is not a substitute for the policy gate, though: --tools eval still does nothing without --unsafe-enable-eval.

  • An unknown name fails at startup and prints the catalog, so a typo can never quietly drop click from the surface.

  • mcp-browser-extension --help prints the full catalog of 42 names to pick from.

Status

v0.5.0 — safe multi-tab concurrency. Adds the batch fan-out tool, makes parallel tab automation race-free (explicit-tabId guard; per-tab chrome.debugger serialization; collision-free tab_new), captures screenshots via chrome.debugger (a specific tab without stealing focus — plus true full-page and element capture), and focuses newly opened tabs by default. 111 automated tests + a gated headed extension smoke.

v0.2.0 — all six build phases complete and green. End-to-end working: npx mcp-browser-extension ⇄ bridge ⇄ extension ⇄ your real Chrome, with a Playwright CDP fallback. v0.2 adds the accessibility snapshot + element refs, auto-wait, cookies/storage/select_option, trusted input (chrome.debugger), a toolbar status badge, and a stable pairing token (--persist-token).

  • Phase 0 — Contracts & skeleton: shared/protocol.ts (wire contract), src/executor/types.ts (Executor interface), src/security/policy.ts (default-deny policy + capability gates), src/config.ts (CLI/env/policy resolution), build + test harness.

  • Phase 1 — MCP server + StubExecutor: mcp/server.ts (clean-stdout stdio), mcp/tools.ts (28-tool catalog + never-throw dispatch + drift-check), validators/envelopes/helpers, ExecutorManager + StubExecutor, cli.ts. Point an MCP host at node dist/src/cli.js today.

  • Phase 2 — WebSocket bridge + auth: bridge/server.ts (loopback WS, hello-token gate, welcome/unauthorized, displacement), bridge/auth.ts (per-boot 256-bit token, atomic-0600 handshake, SHA-256 timingSafeEqual), bridge/connection.ts (id-correlation, method-aware timeouts, backpressure, reject-all-on-close, heartbeat).

  • Phase 3 — ExtensionExecutor + CdpExecutor + selection: executor/extension-executor.ts (Executor over the bridge), executor/cdp-executor.ts (Playwright connect/launch + lock recovery + tab resolution), executor/select.ts (extension-if-ping-responsive else CDP). CLI now starts the bridge, writes the 0600 handshake, and serves a real backend. Adds playwright.

  • Phase 4 — MV3 extension: extension/ — manifest.json, sw/ws-client.ts (dial + hello/welcome + pong), sw/executor.ts (chrome.scripting/chrome.tabs command impls), sw/router.ts (never-throw + drift), sw/background.ts (top-level listeners + 25s keepalive/reconnect), options page (manual pairing), esbuild build → extension-dist/. Verified by a live --load-extension smoke (pair → navigate → get_text). Adds esbuild + @types/chrome.

  • Phase 5 — Helpers, downloads, HITL: hardened download_file (shared/download.ts — path-traversal/dangerous-ext sanitize + size cap, wired into both backends), richer read_as_markdown, and a human-in-the-loop harness (hitl/ — npm run test:hitl [-- --include-mutating]) with pure, unit-tested gating. 50 automated tests.

  • Phase 6 — Packaging & docs: files whitelist (ships dist/src, dist/shared, extension-dist, LICENSE, blueprint — not source/tests), prepack build, bin, quickstart + .mcp.json snippet. Verified by a tarball install smoke (npm pack → install → MCP tools/list).

Security posture (default)

Deny-all safe mode. With no policy configured: empty domain allowlist, eval off, downloads off, mutating tools off. Opt in explicitly:

mcp-browser-extension --allow-domain example.com --enable-mutations
mcp-browser-extension --policy ./policy.json          # see policy.example.json
mcp-browser-extension --unsafe-all-domains            # loud footgun
mcp-browser-extension --enable-observers              # console/network/dialog capture (patches page globals)
mcp-browser-extension --redact                        # scrub secret-shaped strings out of page reads

Allowing a site without a restart. When a call is refused because its site is not allowed, the extension's toolbar icon shows a ?. Click it: the popup lists the blocked site with an Allow button, shows whether the site you are on is allowed (with its own Allow), and lists the allowed sites. The Options page (Settings in the popup) also has a box to allow any other site. An allowed site applies at once to every session sharing that Chrome, and is saved to ~/.mcp-browser-extension/allowed-sites.json so it survives restarts. Sites allowed there can be removed there; sites from --allow-domain stay until the flags change. The catch-all * can only come from --unsafe-all-domains. The agent cannot approve a site itself: MCP Browser Extension never reads or drives the extension's own pages. Run with --no-site-grants to keep the allowlist exactly what the flags say.

What comes back is gated too. The allowlist decides which pages may be read; it says nothing about what is on them. A logged-in page routinely renders a session token into a script tag or an API key onto a settings screen.

  • Password field values are always suppressed — in get_html, and in snapshot, where the field still appears (so you can type into it) flagged secret: true with no value. No flag, no opt-in: nobody wants those characters.

  • --redact additionally scrubs secret-shaped strings — JWTs, AWS/GitHub/Slack/ Google keys, Bearer headers, private-key blocks — out of get_text, get_html, read_as_markdown and eval. It is opt-in because a pattern will eventually fire on something you actually wanted. --redact-pattern <regex> adds your own (and implies --redact); an invalid one fails at startup rather than silently never matching.

  • Redaction runs before the output cap, so a truncated read cannot leak what a full one would have hidden.

Every call is recorded to the task's history.jsonl with the URL it touched, the policy verdict (allowed/denied), how long it took, how many bytes came back, and how many secrets were scrubbed — so "what did the agent do in my browser" has an answer after the fact.

The per-boot 256-bit token in ~/.mcp-browser-extension/handshake.json (mode 0600) is the only trust boundary; it is never written to stdout/stderr. On POSIX the mode is re-verified after every write and the server fails closed if the file ends up group/other-accessible. Windows has no such bits — chmod there only toggles the read-only attribute — so the check is skipped and the token's confidentiality rests on the per-user ACL of %USERPROFILE%\.mcp-browser-extension.

Updates

You don't have to do anything to stay current. The setup snippets above use @latest, and on top of that an installed copy (npx or a global install) checks npm when it starts: if a newer version is published, it starts that version in its place, with the same arguments, so an MCP config written months ago still runs the newest release. The check gives up after 1.5 s when you are offline, and a copy run from a git checkout never updates itself. The new server also refreshes the unpacked extension in ~/mcp-browser-extension, which reloads itself; the Chrome Web Store copy updates through Chrome as usual. Turn it off with --no-auto-update or MCP_BROWSER_EXTENSION_AUTO_UPDATE=0.

Telemetry

The MCP Browser Extension server (not the extension) sends anonymous usage statistics to PostHog, so the project can see how many installs are active, which versions and platforms are in use, and which tools fail most. A notice is printed the first time it runs.

What is sent: a random install id (kept in ~/.mcp-browser-extension/telemetry.json), the server version, OS, CPU architecture and Node major version, whether the session owns the bridge port or shares it, how many browsers are paired, the paired extension's version and whether it is the store or an unpacked copy, and per-tool call and error counts with error codes. The first batch goes out a minute after the first tool call, then every 10 minutes. For PostHog's MCP Analytics view, each tool call is also sent as one $mcp_tool_call event carrying only the tool name and its group (reading, navigation...), its duration, whether it failed and the error code, the MCP client's name and version (such as claude-code), the MCP protocol revision, the AI model when the client names it in its own request metadata (Codex does), and a random session id that changes after 30 idle minutes. When a client connects, one event records that handshake and the names of the tools offered. Nothing an agent sends or reads: no arguments, results, error messages or intents. Batched every 15 seconds. One pair_check event a minute after startup says whether a browser paired and, if not, which of a few fixed reasons applies (no_extension, token_mismatch, version_mismatch, profile_mismatch), so setup problems can be fixed where they happen.

What is never sent: URLs, domains, tool arguments, page content, screenshots, cookies, profile names, tokens, file paths, or anything you type. Events are personless and GeoIP lookup is disabled.

The browser extension sends nothing — it only ever talks to 127.0.0.1.

Turn it off with any of:

MCP_BROWSER_EXTENSION_TELEMETRY=0     # or false / off
DO_NOT_TRACK=1
--no-telemetry             # server flag

Learn more

The full documentation, setup guides for each MCP client and the security model live on the website: MCP Browser Extension docs.

Develop

npm install
npm run typecheck       # server/test sources
npm run typecheck:ext   # extension sources (@types/chrome)
npm run build:ext       # bundle the extension → extension-dist/
npm test                # builds, then runs node --test on dist/test
RUN_EXT_SMOKE=1 node --test dist/test/extension-smoke.test.js   # live, headed

The extension

Published on the Chrome Web Store as MCP Browser Extension. Extension versions move only when extension/ changes, so the listed build can sit a release behind the npm package; the two negotiate capabilities on connect, so an older extension loses features rather than breaking.

For normal use, install from the Chrome Web Store above. The following is only for local development; do not load this unpacked copy in the same Chrome profile as the Store extension. On Windows, Chrome may disable a non-Store build.

extension/ builds (esbuild) to extension-dist/, loaded via chrome://extensions → Load unpacked → select ~/mcp-browser-extension, the mirror the server refreshes from extension-dist/ on every boot (loading extension-dist/ directly also works). It pairs itself from the pairing.json the server writes into that folder; the Options page paste of port + token from ~/.mcp-browser-extension/handshake.json (run npx -y mcp-browser-extension@latest --print-pairing to get the path) is only the fallback.

Reads/interaction use chrome.scripting/chrome.tabs — no "is being debugged" banner, CSP-safe reads (isolated world), testable under Playwright. chrome.debugger is used only where it's needed and worth it: trusted: true input (real OS-level events on React/Vue inputs) and screenshot (captures a specific tab without activating it — safe under parallel batch — with true full-page and element capture). Those ops show the debug banner while attached; the session lingers 1.5s after the last op so a burst of them attaches once. Screenshots are JPEG (quality 70) at CSS-pixel size by default — pass format: "png", quality, or scale to change that.

Available Tools

21 tools
auth_checkA

Is the tab sitting on a sign-in wall? Reads the page (URL, title, password fields, sign-in controls) and returns { authRequired, confidence, signals }. Use it after a navigate, or whenever a step fails unexpectedly, to tell "the session expired" apart from "the agent got lost". Pass failOnAuthWall:true to get an [AUTH_REQUIRED] error instead of a verdict, so a harness can bucket the run as an auth failure.

ParametersJSON Schema
NameRequiredDescriptionDefault
tabIdNoTab id (default: agent's tab)
frameIdNoFrame id from frames_list
allFramesNoAct on the first match in ANY frame (the element may be in an iframe)
failOnAuthWallNoError with [AUTH_REQUIRED] if this lands on a sign-in wall (expired session)

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden, and it does disclose what is inspected, the returned payload keys, and the non-obvious side effect that failOnAuthWall:true converts the verdict into an [AUTH_REQUIRED] error rather than returning data. It does not cover latency, whether it navigates/waits, or false-positive behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core question, then what it reads, then the return shape, then usage, then the flag. Every sentence adds information; nothing is restated from the schema or title.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, and the description compensates by naming the return object's fields ({ authRequired, confidence, signals }). Combined with the usage triggers and the error-mode behavior, an agent has everything needed to call this correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description adds real meaning for failOnAuthWall (error vs verdict, and the harness-bucketing use case) that the schema's one-line hint only gestures at, though tabId/frameId/allFrames are left entirely to the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource up front ('Is the tab sitting on a sign-in wall?') and immediately names the concrete signals it inspects (URL, title, password fields, sign-in controls) plus the verdict shape. An agent can distinguish this from generic readers like snapshot, get_html, or get_text without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear triggering contexts: 'after a navigate, or whenever a step fails unexpectedly', and frames the purpose as disambiguating 'session expired' from 'agent got lost'. It also explains the failOnAuthWall variant for harnesses. It stops short of naming a sibling tool or stating when-not to use it, so it is strong context rather than full alternative routing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

batchA

Run multiple tool calls in one request — parallel (default) or serial. Each op is { tool, args } and goes through the same policy gate, rate limit, and error handling as a direct call. In parallel mode, tab-scoped ops MUST pass an explicit tabId (the active-tab default is unsafe under concurrency). Use to drive several tabs at once (e.g. open tabs, then batch get_text across them). Cannot be nested.

ParametersJSON Schema
NameRequiredDescriptionDefault
opsYesOperations to run; each is a tool name + its args.
modeNoDefault "parallel".
stopOnErrorNoSerial mode only: stop after the first failing op (the rest are skipped).
maxConcurrencyNoParallel mode: max ops in flight at once (default 6).
maxResultBytesNoTotal payload budget across all ops (default 1048576). Ops past the budget are replaced by a one-line summary instead of their content, so a 50-op screenshot/get_html batch cannot flood the caller.

TDQS

A4.8/5.0
Behavior5/5

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 ops go through the same policy gate, rate limit, and error handling as direct calls, warns about concurrency safety for tab-scoped ops, and explains the payload budget behavior (replacing oversized results with summaries). This is thorough and prevents misuse.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise and front-loaded with the core purpose. Each sentence adds value: mode explanation, op format, policy/rate limit note, concurrency warning, usage example, and nesting prohibition. No fluff or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a meta-tool with no output schema, the description covers the critical behavioral aspects: modes, error handling, concurrency, nesting, and payload budget. It does not explicitly describe the return format (e.g., array of results per op), but given the complexity and the fact that it's a wrapper around other tools, this is a minor gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3. The description adds meaningful context beyond the schema: it explains the shape of each op ({ tool, args }), the concurrency requirement for tabId, and the budget replacement behavior. This elevates it above the baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states clearly that the tool runs multiple tool calls in one request, with parallel or serial modes. It distinguishes itself from sibling tools by being a meta-tool, and the 'Cannot be nested' constraint adds further specificity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit usage guidance: 'Use to drive several tabs at once (e.g. open tabs, then batch get_text across them)' and warns about the need for explicit tabId in parallel mode. It also explains the stopOnError and maxResultBytes behaviors, making it clear when to use each mode.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

chrome_statusA

Report backend/session status: paired browser profiles and how each was named, and flags for switched-off capabilities.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. The word 'Report' implies a read-only operation and the sentence does indicate the kind of information returned, but it does not explicitly state side-effect freedom, backend interaction, or how capabilities are determined.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single well-structured sentence with the verb and resource front-loaded, followed by concrete output details. Every phrase adds useful content and there is no redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a no-parameter status tool, the description covers the major expected output categories: paired profiles, profile naming, and disabled capability flags. It does not describe the return structure or formatting, but the low complexity and absent output schema make the description largely sufficient.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters and the schema is empty, so there is nothing meaningful for the description to add. Per the baseline for zero-parameter tools, this is handled appropriately without parameter documentation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses the verb 'Report' with a specific resource, 'backend/session status', then enumerates what is included: paired browser profiles, how they were named, and capability flags. This clearly distinguishes it from the sibling status/auth/profile tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no guidance about when to use this tool relative to similarly named siblings such as auth_check or task_status, and no exclusions or alternatives are mentioned. The only implication is that it provides status information, which is too weak to route an agent correctly.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

frames_listA

List the tab's frames (the top document plus every iframe the extension can reach), with each frame's id and URL. Use it when a selector that should match does not: the element is probably in one of these frames, and you can then pass frameId (or allFrames:true) to act inside it.

ParametersJSON Schema
NameRequiredDescriptionDefault
tabIdNoTab id (default: agent's tab)

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are supplied, so the description carries the behavioral burden. It discloses the reachability limitation ('every iframe the extension can reach') and the shape of the result, and 'List' implies a read-only, side-effect-free operation. It does not state error behavior for unreachable frames or any permission constraints, so it falls short of fully covering a no-annotation tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, no filler: the first defines what is listed and returned, the second gives the trigger and the follow-up action. The most actionable content (when to reach for this tool) is placed second but still immediately readable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema or annotations, so the description must explain returns and behavior; it does name the returned fields (id and URL) and the frame-reachability caveat. It leaves unanswered what happens when no frames are found or when an iframe is unreachable, which for a no-annotation tool is a modest but real gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the single tabId parameter is already documented with its default ('agent's tab'), so baseline is 3. The description mentions frameId/allFrames:true, but those belong to other tools rather than clarifying this tool's input; it adds no syntax or format detail about tabId itself.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('List the tab's frames') and defines scope precisely: 'the top document plus every iframe the extension can reach'. It also names the return contents (frame id and URL), which lets an agent distinguish it from tabs_list without opening schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit trigger condition — 'Use it when a selector that should match does not' — and a concrete next step ('pass frameId (or allFrames:true) to act inside it'). This is a when-to-use rule tied to observable failure, which is exactly what an agent needs.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_cookiesC

Read cookies visible to the tab's URL (or a given url).

ParametersJSON Schema
NameRequiredDescriptionDefault
urlNo
tabIdNoTab id (default: agent's tab)

TDQS

C2.9/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It discloses only that reads target the tab URL or an explicit url; it omits permission/auth requirements, whether httpOnly/secure cookies are included, and the return shape. This is thin for a network-adjacent read tool with no annotation coverage.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single tight sentence with no wasted words, front-loaded with the verb and resource. It is efficient, though the brevity contributes to under-specification rather than maximal clarity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No annotations, no output schema, and only 50% parameter coverage mean the description should do more. It fails to address permissions, cookie visibility rules, or the return format an agent needs to interpret results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 50%: tabId is documented inline (default agent's tab) but url has no schema description, and the description only implies url overrides the tab. It adds marginal meaning to the undocumented url parameter without fully compensating for the coverage gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Read) plus resource (cookies) and clarifies the scope: cookies visible to the tab's URL or a supplied url. It is clear what the tool returns, though it does not differentiate itself from siblings like storage or snapshot that an agent might confuse with session data retrieval.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no when-to-use or when-not-to-use guidance, and no alternative is named. The description hints at a url override but gives no condition for choosing between the tab's URL and an explicit url.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_htmlA

Get HTML of the page or an element. Output is capped (see maxBytes) and cut at a tag boundary; narrow it with selector rather than raising the cap when you can. Password field values are always blanked.

ParametersJSON Schema
NameRequiredDescriptionDefault
refNoElement ref from a snapshot
outerNo
tabIdNoTab id (default: agent's tab)
frameIdNoFrame id from frames_list
maxBytesNoCap returned content at N UTF-8 bytes (default 262144); the full payload still lands in results/
selectorNoCSS selector (or pass ref)
allFramesNoAct on the first match in ANY frame (the element may be in an iframe)

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations the description carries the full burden, and it does disclose two non-obvious behaviors: output is capped and truncated at a tag boundary, and password field values are always blanked (a security-relevant behavior an agent should know). It omits auth/permission requirements and error behavior, but the disclosed traits are meaningful.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, front-loaded with what the tool returns before the caveats. Every sentence carries information: scope, truncation behavior, and a selection tip.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 7-parameter tool with no output schema, the description covers the essential return-shape caveats (byte cap, tag-boundary cut, blanked passwords) that the schema cannot express. Remaining gaps — default targeting when neither ref nor selector is given, and full-payload retrieval — are partly covered by the schema's maxBytes note.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 86%, so the schema already documents ref, tabId, frameId, maxBytes, selector and allFrames. The description adds only cross-parameter advice about maxBytes and selector rather than new per-parameter meaning, which is the expected baseline when the schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Get HTML of the page or an element') and immediately scopes what is returned, so an agent can tell it apart from text/markdown extraction siblings. It stops short of naming any sibling (get_text, read_as_markdown, snapshot) to differentiate itself explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Offers one concrete usage rule — narrow with `selector` rather than raising the cap — which is real guidance. However, it gives no when-to-use versus the sibling HTML/text/markdown extraction tools, and no prerequisites, so routing remains largely inferred.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_textC

Get visible text of the page or an element.

ParametersJSON Schema
NameRequiredDescriptionDefault
refNoElement ref from a snapshot
tabIdNoTab id (default: agent's tab)
frameIdNoFrame id from frames_list
maxBytesNoCap returned content at N UTF-8 bytes (default 262144); the full payload still lands in results/
selectorNoCSS selector (or pass ref)
allFramesNoAct on the first match in ANY frame (the element may be in an iframe)

TDQS

C2.9/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. 'Visible text' hints at rendered/visibility-aware extraction rather than raw markup, but nothing is said about return shape, truncation behavior, frame handling, or tab defaults beyond what the schema already states.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single, front-loaded sentence with zero waste. Nothing is padded or redundant.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With six optional parameters, no output schema, and no annotations, the description is thin: it omits return format, how ref/selector/allFrames interact, and how it relates to the several sibling tools that also read page content. The agent is left to open the schema and guess at routing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all six parameters (ref, tabId, frameId, maxBytes, selector, allFrames) are already documented in the schema. The description adds no syntax, defaults, or precedence rules beyond that, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Get) and resource (visible text of the page or an element), which is meaningfully more precise than a generic 'read' tool. However, it does not differentiate itself from close siblings like get_html, read_as_markdown, or snapshot, leaving the agent to infer the distinction.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance on when to use this versus get_html, read_as_markdown, or snapshot, all of which return overlapping content. No mention of prerequisites (e.g., needing a ref from snapshot) or when an element-level read is preferable to a page-level read.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

profile_renameA

Rename an automatically named browser profile (e.g. "profile-2" -> "work"). The name sticks across restarts; its saved artifacts move with it.

ParametersJSON Schema
NameRequiredDescriptionDefault
toYesNew profile name
fromYesCurrent profile name

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden of behavioral disclosure. It explicitly states the name persists across restarts and that saved artifacts move with the profile, which are important side effects. However, it does not mention error conditions, permissions, or reversibility, so it is informative but not exhaustive.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences with no fluff. The action is front-loaded, and the second sentence adds key behavioral context without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple rename tool with two string parameters and no output schema, the description covers the purpose and two important behavioral aspects. It is sufficient for an agent to understand how to call it, though it does not cover edge cases like non-existent profiles or naming constraints.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Both parameters are fully described in the schema ('from' and 'to'), and the description provides a concrete example that clarifies expected formats. Since schema coverage is 100%, the description adds marginal value beyond the schema, but the example helps grounding.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool renames browser profiles, with a concrete example ('profile-2' -> 'work'). It identifies the resource (browser profile) and the action (rename), distinguishing it from sibling profile_use which selects profiles rather than renames them.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage for renaming automatically named profiles, but does not explicitly state when to use it over alternatives or any exclusions. It provides context (names stick, artifacts move) but lacks direct guidance on selection criteria.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

profile_useA

Switch the active browser profile (identity). Subsequent downloads, results, screenshots, and the action log are stored under profiles//. Resets the active task to "default" unless you then call task_new.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesProfile name (becomes a folder; sanitized to a safe path segment).

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Without annotations, the description carries the full burden. It discloses two behavioral traits: storage location change and task reset. No contradictions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with purpose. Every sentence adds value with no redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter tool with no output schema, the description covers purpose, storage effect, and task side effect. It is sufficiently complete for an AI agent to use correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema has 100% coverage, so baseline is 3. The description adds no additional meaning about the 'name' parameter beyond what the schema already provides (folder creation, sanitization).

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb 'Switch' and resource 'active browser profile (identity)', clearly distinguishing it from other browser actions like navigate or click. The purpose is immediately clear.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explains when to use the tool by stating that subsequent actions are stored under profiles/<name>/ and that it resets the active task to 'default' unless task_new is called. It does not explicitly state when not to use it, but the guidance is adequate.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

proxy_statusB

The active profile's proxy and the IP sites see. The user sets it per Chrome profile; for another IP, profile_use another profile.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

B3.3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full disclosure burden. It adds useful context that the proxy is configured per Chrome profile and that the reported IP is what remote sites see, but it says nothing about prerequisites (an active/connected browser session), whether it is a safe read, or what happens when no profile is active.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences with no filler and the key subject (proxy + observed IP) front-loaded. The only flaw is the garbled second clause, which costs clarity but not length.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-param status tool there is no output schema, so the description must describe the return value. It names the two returned facts (proxy, visible IP) but does not describe the shape or format of the response or any failure state, leaving the agent to guess the payload.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so there is nothing for the description to disambiguate; the baseline of 4 applies. The description correctly implies no inputs are needed, consistent with the empty schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose3/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description conveys what the tool surfaces — the active profile's proxy and the IP that sites observe — but it is a sentence fragment with no verb, and it never distinguishes itself from the sibling chrome_status. An agent can infer it is a read/status tool, but the purpose is only implied rather than stated.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It names an alternative route ('for another IP, profile_use another profile'), which is genuine routing guidance, but it never states the positive condition for calling this tool (e.g. 'call this to verify the current egress IP'). Usage is implied rather than prescribed.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

read_as_markdownC

Read the page (or subtree) as readable markdown.

ParametersJSON Schema
NameRequiredDescriptionDefault
tabIdNoTab id (default: agent's tab)
frameIdNoFrame id from frames_list
maxBytesNoCap returned content at N UTF-8 bytes (default 262144); the full payload still lands in results/
selectorNo
allFramesNoAct on the first match in ANY frame (the element may be in an iframe)

TDQS

C2.9/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden. It says nothing about authentication requirements, side effects, dynamic content handling, rate limits, or how the 'readable markdown' is produced; only the output format is mentioned.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, front-loaded sentence with no filler. Every word contributes to stating the action, target, and output format.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given five parameters, no annotations, and no output schema, the description is too thin. It omits usage context, behavioral traits, and any explanation of how maxBytes, frame targeting, or allFrames affect the result.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 80%, which meets the high-coverage baseline. The description adds only a hint about subtree scope via '(or subtree)', which loosely relates to the undocumented selector parameter, but it otherwise does not clarify any parameter semantics beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a clear verb ('Read') and resource ('page (or subtree)') plus the output format ('readable markdown'). It distinguishes from siblings like get_text and get_html by naming markdown, but it does not explicitly contrast itself with those alternatives.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no when-to-use guidance, no exclusions, and no named alternatives. An agent can infer that this tool is for reading page content as markdown, but the description does not say when to choose it over get_text, get_html, or snapshot.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

screenshotB

Capture a screenshot (page or element). Default is JPEG (quality 70) at CSS-pixel size, which is several times smaller than PNG and reads fine. Pass format:"png" for lossless, quality 1-100 for JPEG, scale 2 for device pixels on a Retina display or 0.5 to shrink.

ParametersJSON Schema
NameRequiredDescriptionDefault
refNoElement ref from a snapshot
scaleNo
tabIdNoTab id (default: agent's tab)
formatNo
frameIdNoFrame id from frames_list
qualityNo
fullPageNo
selectorNoCSS selector (or pass ref)
allFramesNoAct on the first match in ANY frame (the element may be in an iframe)

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden, and it does disclose useful defaults (JPEG q70, CSS-pixel size) and the rationale (smaller than PNG). It omits what the call returns (image payload, file path, base64), and says nothing about permissions, tab targeting side effects, or rate/large-page limits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences, front-loaded with the default behavior and size rationale before the overrides. No filler, though the format/quality/scale instructions are packed densely enough to require a careful read.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 9-parameter tool with no annotations and no output schema, the description should explain the return payload and how ref/selector/fullPage/allFrames interact. It covers the imaging knobs well but leaves selection semantics and the response shape unaddressed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 56%, and the description adds genuine meaning to three params: format tradeoffs, quality 1-100 as JPEG-only, and scale 2 for Retina / 0.5 to shrink. The remaining params (ref, selector, fullPage, allFrames, frameId, tabId) rely on terse schema strings, so the description only partially compensates for the coverage gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Capture a screenshot') and clarifies the two scopes it supports (page or element). It does not, however, distinguish itself from close siblings like snapshot, print_pdf, or get_html, which an agent would need to pick between.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives practical guidance on format/quality/scale tradeoffs, which implies the default choice. But it never says when to prefer this over snapshot or print_pdf, nor when an element vs full-page capture is appropriate, leaving the use-vs-alternative decision to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

snapshotB

Accessibility snapshot: interactive elements with refs to target by ref (more reliable than guessing CSS selectors). Pass diff:true to get only what changed since the last snapshot of this tab - far cheaper in a click/read loop. Password fields appear as secret:true with no value.

ParametersJSON Schema
NameRequiredDescriptionDefault
maxNo
diffNoReturn added/removed/changed elements since the previous snapshot of this tab instead of the whole tree
tabIdNoTab id (default: agent's tab)
frameIdNoFrame id from frames_list
allFramesNoAct on the first match in ANY frame (the element may be in an iframe)
failOnAuthWallNoError with [AUTH_REQUIRED] if this lands on a sign-in wall (expired session)
interactiveOnlyNo

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations the description carries the full burden. It usefully discloses that the last snapshot defines the diff baseline, and that password fields are masked as secret:true with no value. It omits broader behavior: return shape, auth-wall handling (only hinted via the schema's failOnAuthWall), frame scoping, and error behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences with the primary purpose front-loaded and each clause carrying weight (ref targeting, diff cost, secret fields). Parentheticals are dense but not wasteful; it could be marginally cleaner but there is no filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 7-parameter, annotation-free tool with no output schema, the description covers diff, refs, and password masking but says nothing about max, tabId/frameId/allFrames scoping, interactiveOnly, or the returned tree structure. Adequate but with clear gaps an agent must infer from the schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 71%, so the schema documents most parameters itself (diff, tabId, frameId, allFrames, failOnAuthWall). The description adds only the diff baseline semantics and the secret-field note, not new meaning for max or interactiveOnly. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific artifact (accessibility snapshot of interactive elements) and the key output (refs for targeting). It implicitly distinguishes itself from get_html/get_text/screenshot by emphasizing ref-based targeting and reliability over CSS selectors, but it never names a sibling directly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explains the click/read loop use case and recommends diff:true as cheaper, which implies usage. However it never states when to prefer this over get_html, read_as_markdown, or screenshot, and gives no explicit exclusions or preconditions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

storageC

Read/write localStorage (or sessionStorage). op: get|set|remove|clear.

ParametersJSON Schema
NameRequiredDescriptionDefault
opYes
keyNo
tabIdNoTab id (default: agent's tab)
valueNo
sessionNo

TDQS

C2.7/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It says 'read/write' but does not flag that set/remove mutate persistent state or that clear wipes all storage destructively, nor does it describe permissions or reversibility. The parenthetical '(or sessionStorage)' hints at a storage-type toggle but never explains how it is selected.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence with zero filler, stating the resource and the operation set first. It is efficient, though the extreme terseness is closer to under-specification than to disciplined concision.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema, no annotations, and a 5-parameter mutating tool with 20% schema coverage leaves the definition far from complete. An agent cannot determine per-op argument requirements, the meaning of 'session', or the destructive scope of 'clear' from this description.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is only 20% (just tabId), so the description must compensate. It adds almost nothing: the op enumeration duplicates the schema enum, and the sessionStorage reference does not explain the 'session' boolean. It never states that set requires value, that get/remove require key, or what happens if key is omitted on clear.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific resource (localStorage/sessionStorage) and the full set of operations, so the agent immediately knows this is a browser storage accessor. It distinguishes itself implicitly from get_cookies, but never names or contrasts any sibling tool explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives no when-to-use guidance, no prerequisites, and no routing to alternatives. An agent must infer that this is the tool for storage reads/writes versus get_cookies or the snapshot tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

tabs_listA

List open browser tabs.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A3.7/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description must disclose behaviors. It mentions listing tabs but does not specify the format or content of the output (e.g., titles, URLs, IDs). The agent lacks insight into what the list contains.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise (5 words) and front-loaded. Every word is necessary and informative.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple list tool with no output schema, the description provides the basic function but fails to clarify what data is returned. It is marginally complete given the tool's simplicity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There are zero parameters, so the schema is empty. The description adds value by stating the purpose, which is sufficient for a parameterless tool. Baseline 4 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description 'List open browser tabs' clearly identifies the verb (list) and resource (open browser tabs). It distinguishes from sibling tools like tab_new, tab_close, and tab_select, which perform different actions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage for retrieving open tabs but provides no explicit guidance on when to use this tool versus alternatives (e.g., tab_select, tab_new). No when-not-to-use scenarios are mentioned.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

task_newA

Start a new task (run) under the active profile. Creates profiles//tasks// with downloads/, results/, screenshots/ and makes it the active task so all captured artifacts land there.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesTask name (becomes a folder; sanitized to a safe path segment).

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full burden. It discloses directory creation and active task setting, but lacks details on overwriting behavior, error conditions, or required permissions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, no redundant information. The first sentence front-loads the action, and the second provides essential behavioral details concisely.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the simple single-parameter tool and no output schema, the description adequately explains the creation process and side effects. It could mention duplicate name behavior for completeness.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% with a clear parameter description. The tool description reinforces the folder creation context but adds minimal value beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'Start a new task (run) under the active profile,' specifying the verb and resource. It distinguishes from sibling tools like tasks_list (listing) and task_status (status) by focusing on creation and activation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit guidance on when to use this tool versus alternatives (e.g., batch or tab_new). The description does not provide when-not conditions or alternative tool references.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

tasks_listA

List every task across all profiles under the data dir, with sizes and download counts.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A3.6/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description must carry full burden. It merely states the action and output fields, but omits behavioral traits: performance implications, permission requirements, potential for large data volumes, or edge cases (e.g., no tasks found).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Single sentence, front-loaded with verb and resource. Every word adds value: 'every task', 'across all profiles', 'with sizes and download counts'. No fluff or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter, no-output-schema tool, the description covers the essential purpose and output. However, it lacks any mention of the 'data dir' location, performance scale, or relationship to sibling task tools, missing some completeness for context-rich decision-making.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

No parameters in the schema; baseline 4 applies. The description adds no parameter info, but none is needed. Schema coverage is 100% by virtue of being empty.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states the verb 'List', the resource 'tasks', and the scope 'across all profiles under the data dir'. Specifies included data: sizes and download counts. Distinguishes from sibling tools like task_new and task_status by focusing on listing.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance on when to use this tool versus alternatives like task_new (create) or task_status (check status). Does not mention any contextual triggers or exclusions, leaving the agent to infer usage without support.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

task_statusA

Report the active profile/task and the folder paths where this run's artifacts are stored.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description should explicitly state read-only behavior. It says 'report', implying no side effects, but does not confirm it does not modify state or have rate limits. Barely adequate.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Single sentence, front-loaded with purpose, no extraneous words. Excellent conciseness.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the key information reported (active profile/task and folder paths). No output schema exists, but the return values are implied. Slightly vague on what 'active' means, but sufficient for a simple status tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has zero parameters and 100% coverage, so the description does not need to add parameter details. Baseline 4 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool reports the active profile/task and artifact folder paths, using a specific verb 'report' and specifying the exact resources. This distinguishes it from sibling tools like tasks_list which list all tasks.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance on when to use this tool versus alternatives such as tasks_list or chrome_status. The description does not mention preconditions or when it is appropriate to call it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

wait_forC

Wait for a selector or text to appear/disappear.

ParametersJSON Schema
NameRequiredDescriptionDefault
goneNo
tabIdNoTab id (default: agent's tab)
frameIdNoFrame id from frames_list
selectorNo
allFramesNoAct on the first match in ANY frame (the element may be in an iframe)
timeoutMsNo
textContainsNo
failOnAuthWallNoError with [AUTH_REQUIRED] if this lands on a sign-in wall (expired session)

TDQS

C2.4/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden and mostly fails: it does not say what the default timeout is, what happens on timeout (error vs. empty return), whether the call blocks, or how failOnAuthWall/[AUTH_REQUIRED] surfaces. The appear/disappear toggle is mentioned but not tied to any parameter.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single short sentence front-loads the core action and wastes no words. However, its brevity reflects under-specification rather than disciplined concision — key qualifiers were omitted rather than compressed.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For an 8-parameter, zero-required tool with no annotations, no output schema, and half its parameters undocumented, one sentence is far too thin. Nothing tells the agent about blocking behavior, default timeouts, or the interaction between selector, textContains, and gone.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Only 50% of the 8 parameters are described in the schema (tabId, frameId, allFrames, failOnAuthWall); selector, textContains, gone, and timeoutMs are undocumented. The description gestures at 'selector or text' and 'appear/disappear' but never states that `gone` inverts the check or that selector/textContains are alternatives, so it does not compensate for the coverage gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose3/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a recognizable verb and object (wait for a selector or text), so the general intent is clear. But it never explains how the appear-vs-disappear behavior is selected, nor distinguishes this from siblings like snapshot or get_text that also inspect page state. Adequate but with real gaps.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no when-to-use guidance, no prerequisites, and no mention of alternatives such as snapshot/get_text/frames_list. An agent must infer entirely from the name that this is for blocking on page readiness.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 13 tool updatesv0.9.24
    • Changedauth_check1 field changed
      • changedInput schema / properties / tabId / description
        Previous value: -"Tab id (default: active tab)"New value: +"Tab id (default: agent's tab)"
    • Changedextract_links1 field changed
      • changedInput schema / properties / tabId / description
        Previous value: -"Tab id (default: active tab)"New value: +"Tab id (default: agent's tab)"
    • Changedframes_list1 field changed
      • changedInput schema / properties / tabId / description
        Previous value: -"Tab id (default: active tab)"New value: +"Tab id (default: agent's tab)"
    • Changedget_cookies1 field changed
      • changedInput schema / properties / tabId / description
        Previous value: -"Tab id (default: active tab)"New value: +"Tab id (default: agent's tab)"
    • Changedget_html1 field changed
      • changedInput schema / properties / tabId / description
        Previous value: -"Tab id (default: active tab)"New value: +"Tab id (default: agent's tab)"
    • Changedget_text1 field changed
      • changedInput schema / properties / tabId / description
        Previous value: -"Tab id (default: active tab)"New value: +"Tab id (default: agent's tab)"
    • Changedprint_pdf1 field changed
      • changedInput schema / properties / tabId / description
        Previous value: -"Tab id (default: active tab)"New value: +"Tab id (default: agent's tab)"
    • Addedproxy_status
    • Changedread_as_markdown1 field changed
      • changedInput schema / properties / tabId / description
        Previous value: -"Tab id (default: active tab)"New value: +"Tab id (default: agent's tab)"
    • Changedscreenshot1 field changed
      • changedInput schema / properties / tabId / description
        Previous value: -"Tab id (default: active tab)"New value: +"Tab id (default: agent's tab)"
    • Changedsnapshot1 field changed
      • changedInput schema / properties / tabId / description
        Previous value: -"Tab id (default: active tab)"New value: +"Tab id (default: agent's tab)"
    • Changedstorage1 field changed
      • changedInput schema / properties / tabId / description
        Previous value: -"Tab id (default: active tab)"New value: +"Tab id (default: agent's tab)"
    • Changedwait_for1 field changed
      • changedInput schema / properties / tabId / description
        Previous value: -"Tab id (default: active tab)"New value: +"Tab id (default: agent's tab)"
  2. 20 tool updatesv0.9.11
    • Removedback
    • Removedclick
    • Removedconsole_logs
    • Removeddialogs
    • Removeddownload_file
    • Removedeval
    • Removedfill_form
    • Removedforward
    • Removedhover
    • Removednavigate
    • Removednetwork_log
    • Removedpress
    • Removedreload
    • Removedscroll
    • Removedselect_option
    • Removedtab_close
    • Removedtab_new
    • Removedtab_select
    • Removedtype
    • Removedupload_file
  3. 30 tool updatesv0.9.5
    • Changedauth_check4 fields changed
      • changedInput schema / properties / allFrames / description
        Previous value: -"Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)"New value: +"Act on the first match in ANY frame (the element may be in an iframe)"
      • changedInput schema / properties / failOnAuthWall / description
        Previous value: -"Fail with [AUTH_REQUIRED] when the page this call lands on is a high-confidence sign-in wall (session expired). Off by default unless the server runs with --fail-on-auth-wall; snapshot still reports the verdict as `authWall` either way."New value: +"Error with [AUTH_REQUIRED] if this lands on a sign-in wall (expired session)"
      • changedInput schema / properties / frameId / description
        Previous value: -"Act inside this frame (ids come from frames_list)"New value: +"Frame id from frames_list"
      • changedInput schema / properties / tabId / description
        Previous value: -"Target tab id (defaults to the active tab)"New value: +"Tab id (default: active tab)"
    • Changedback2 fields changed
      • changedInput schema / properties / failOnAuthWall / description
        Previous value: -"Fail with [AUTH_REQUIRED] when the page this call lands on is a high-confidence sign-in wall (session expired). Off by default unless the server runs with --fail-on-auth-wall; snapshot still reports the verdict as `authWall` either way."New value: +"Error with [AUTH_REQUIRED] if this lands on a sign-in wall (expired session)"
      • changedInput schema / properties / tabId / description
        Previous value: -"Target tab id (defaults to the active tab)"New value: +"Tab id (default: active tab)"
    • Changedclick10 fields changed
      • changedInput schema / properties / allFrames / description
        Previous value: -"Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)"New value: +"Act on the first match in ANY frame (the element may be in an iframe)"
      • changedInput schema / properties / failOnAuthWall / description
        Previous value: -"Fail with [AUTH_REQUIRED] when the page this call lands on is a high-confidence sign-in wall (session expired). Off by default unless the server runs with --fail-on-auth-wall; snapshot still reports the verdict as `authWall` either way."New value: +"Error with [AUTH_REQUIRED] if this lands on a sign-in wall (expired session)"
      • changedInput schema / properties / frameId / description
        Previous value: -"Act inside this frame (ids come from frames_list)"New value: +"Frame id from frames_list"
      • changedInput schema / properties / name / description
        Previous value: -"Target by accessible name/visible label (pairs with role)"New value: +"Accessible name / visible label (pair with role)"
      • changedInput schema / properties / nth / description
        Previous value: -"Pick the nth (0-based) match when a role+name locator is legitimately ambiguous"New value: +"0-based index when role+name is ambiguous"
      • changedInput schema / properties / ref / description
        Previous value: -"Element ref from a prior read (exactly one of selector|ref)"New value: +"Element ref from a snapshot"
      • changedInput schema / properties / role / description
        Previous value: -"Target by ARIA role (e.g. button, link, textbox) - alternative to selector/ref"New value: +"ARIA role, e.g. button|link|textbox (pair with name)"
      • changedInput schema / properties / selector / description
        Previous value: -"CSS selector (exactly one of selector|ref)"New value: +"CSS selector (or ref, or role+name)"
      • changedInput schema / properties / snapshotAfter / description
        Previous value: -"Return what CHANGED on the page after this action (added/removed/changed elements vs the last snapshot) instead of making you re-read the page"New value: +"Return what CHANGED on the page after this action instead of making you re-read it"
      • changedInput schema / properties / tabId / description
        Previous value: -"Target tab id (defaults to the active tab)"New value: +"Tab id (default: active tab)"
    • Changedconsole_logs3 fields changed
      • changedInput schema / properties / allFrames / description
        Previous value: -"Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)"New value: +"Act on the first match in ANY frame (the element may be in an iframe)"
      • changedInput schema / properties / frameId / description
        Previous value: -"Act inside this frame (ids come from frames_list)"New value: +"Frame id from frames_list"
      • changedInput schema / properties / tabId / description
        Previous value: -"Target tab id (defaults to the active tab)"New value: +"Tab id (default: active tab)"
    • Changeddialogs3 fields changed
      • changedInput schema / properties / allFrames / description
        Previous value: -"Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)"New value: +"Act on the first match in ANY frame (the element may be in an iframe)"
      • changedInput schema / properties / frameId / description
        Previous value: -"Act inside this frame (ids come from frames_list)"New value: +"Frame id from frames_list"
      • changedInput schema / properties / tabId / description
        Previous value: -"Target tab id (defaults to the active tab)"New value: +"Tab id (default: active tab)"
    • Changeddownload_file3 fields changed
      • changedInput schema / properties / ref / description
        Previous value: -"Element ref from a prior read (exactly one of selector|ref)"New value: +"Element ref from a snapshot"
      • changedInput schema / properties / selector / description
        Previous value: -"CSS selector (exactly one of selector|ref)"New value: +"CSS selector (or pass ref)"
      • changedInput schema / properties / tabId / description
        Previous value: -"Target tab id (defaults to the active tab)"New value: +"Tab id (default: active tab)"
    • Changedeval3 fields changed
      • changedInput schema / properties / allFrames / description
        Previous value: -"Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)"New value: +"Act on the first match in ANY frame (the element may be in an iframe)"
      • changedInput schema / properties / frameId / description
        Previous value: -"Act inside this frame (ids come from frames_list)"New value: +"Frame id from frames_list"
      • changedInput schema / properties / tabId / description
        Previous value: -"Target tab id (defaults to the active tab)"New value: +"Tab id (default: active tab)"
    • Changedextract_links3 fields changed
      • changedInput schema / properties / allFrames / description
        Previous value: -"Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)"New value: +"Act on the first match in ANY frame (the element may be in an iframe)"
      • changedInput schema / properties / frameId / description
        Previous value: -"Act inside this frame (ids come from frames_list)"New value: +"Frame id from frames_list"
      • changedInput schema / properties / tabId / description
        Previous value: -"Target tab id (defaults to the active tab)"New value: +"Tab id (default: active tab)"
    • Changedfill_form4 fields changed
      • changedInput schema / properties / allFrames / description
        Previous value: -"Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)"New value: +"Act on the first match in ANY frame (the element may be in an iframe)"
      • changedInput schema / properties / failOnAuthWall / description
        Previous value: -"Fail with [AUTH_REQUIRED] when the page this call lands on is a high-confidence sign-in wall (session expired). Off by default unless the server runs with --fail-on-auth-wall; snapshot still reports the verdict as `authWall` either way."New value: +"Error with [AUTH_REQUIRED] if this lands on a sign-in wall (expired session)"
      • changedInput schema / properties / frameId / description
        Previous value: -"Act inside this frame (ids come from frames_list)"New value: +"Frame id from frames_list"
      • changedInput schema / properties / tabId / description
        Previous value: -"Target tab id (defaults to the active tab)"New value: +"Tab id (default: active tab)"
    • Changedforward2 fields changed
      • changedInput schema / properties / failOnAuthWall / description
        Previous value: -"Fail with [AUTH_REQUIRED] when the page this call lands on is a high-confidence sign-in wall (session expired). Off by default unless the server runs with --fail-on-auth-wall; snapshot still reports the verdict as `authWall` either way."New value: +"Error with [AUTH_REQUIRED] if this lands on a sign-in wall (expired session)"
      • changedInput schema / properties / tabId / description
        Previous value: -"Target tab id (defaults to the active tab)"New value: +"Tab id (default: active tab)"
    • Changedframes_list1 field changed
      • changedInput schema / properties / tabId / description
        Previous value: -"Target tab id (defaults to the active tab)"New value: +"Tab id (default: active tab)"
    • Changedget_cookies1 field changed
      • changedInput schema / properties / tabId / description
        Previous value: -"Target tab id (defaults to the active tab)"New value: +"Tab id (default: active tab)"
    • Changedget_html6 fields changed
      • changedInput schema / properties / allFrames / description
        Previous value: -"Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)"New value: +"Act on the first match in ANY frame (the element may be in an iframe)"
      • changedInput schema / properties / frameId / description
        Previous value: -"Act inside this frame (ids come from frames_list)"New value: +"Frame id from frames_list"
      • changedInput schema / properties / maxBytes / description
        Previous value: -"Cap the returned content at this many UTF-8 bytes (default 262144). A truncated result reports truncated/totalBytes/returnedBytes. The full payload is still written to the task's results/ dir."New value: +"Cap returned content at N UTF-8 bytes (default 262144); the full payload still lands in results/"
      • changedInput schema / properties / ref / description
        Previous value: -"Element ref from a prior read (exactly one of selector|ref)"New value: +"Element ref from a snapshot"
      • changedInput schema / properties / selector / description
        Previous value: -"CSS selector (exactly one of selector|ref)"New value: +"CSS selector (or pass ref)"
      • changedInput schema / properties / tabId / description
        Previous value: -"Target tab id (defaults to the active tab)"New value: +"Tab id (default: active tab)"
    • Changedget_text6 fields changed
      • changedInput schema / properties / allFrames / description
        Previous value: -"Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)"New value: +"Act on the first match in ANY frame (the element may be in an iframe)"
      • changedInput schema / properties / frameId / description
        Previous value: -"Act inside this frame (ids come from frames_list)"New value: +"Frame id from frames_list"
      • changedInput schema / properties / maxBytes / description
        Previous value: -"Cap the returned content at this many UTF-8 bytes (default 262144). A truncated result reports truncated/totalBytes/returnedBytes. The full payload is still written to the task's results/ dir."New value: +"Cap returned content at N UTF-8 bytes (default 262144); the full payload still lands in results/"
      • changedInput schema / properties / ref / description
        Previous value: -"Element ref from a prior read (exactly one of selector|ref)"New value: +"Element ref from a snapshot"
      • changedInput schema / properties / selector / description
        Previous value: -"CSS selector (exactly one of selector|ref)"New value: +"CSS selector (or pass ref)"
      • changedInput schema / properties / tabId / description
        Previous value: -"Target tab id (defaults to the active tab)"New value: +"Tab id (default: active tab)"
    • Changedhover9 fields changed
      • changedInput schema / properties / allFrames / description
        Previous value: -"Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)"New value: +"Act on the first match in ANY frame (the element may be in an iframe)"
      • changedInput schema / properties / frameId / description
        Previous value: -"Act inside this frame (ids come from frames_list)"New value: +"Frame id from frames_list"
      • changedInput schema / properties / name / description
        Previous value: -"Target by accessible name/visible label (pairs with role)"New value: +"Accessible name / visible label (pair with role)"
      • changedInput schema / properties / nth / description
        Previous value: -"Pick the nth (0-based) match when a role+name locator is legitimately ambiguous"New value: +"0-based index when role+name is ambiguous"
      • changedInput schema / properties / ref / description
        Previous value: -"Element ref from a prior read (exactly one of selector|ref)"New value: +"Element ref from a snapshot"
      • changedInput schema / properties / role / description
        Previous value: -"Target by ARIA role (e.g. button, link, textbox) - alternative to selector/ref"New value: +"ARIA role, e.g. button|link|textbox (pair with name)"
      • changedInput schema / properties / selector / description
        Previous value: -"CSS selector (exactly one of selector|ref)"New value: +"CSS selector (or ref, or role+name)"
      • changedInput schema / properties / snapshotAfter / description
        Previous value: -"Return what CHANGED on the page after this action (added/removed/changed elements vs the last snapshot) instead of making you re-read the page"New value: +"Return what CHANGED on the page after this action instead of making you re-read it"
      • changedInput schema / properties / tabId / description
        Previous value: -"Target tab id (defaults to the active tab)"New value: +"Tab id (default: active tab)"
    • Changednavigate2 fields changed
      • changedInput schema / properties / failOnAuthWall / description
        Previous value: -"Fail with [AUTH_REQUIRED] when the page this call lands on is a high-confidence sign-in wall (session expired). Off by default unless the server runs with --fail-on-auth-wall; snapshot still reports the verdict as `authWall` either way."New value: +"Error with [AUTH_REQUIRED] if this lands on a sign-in wall (expired session)"
      • changedInput schema / properties / tabId / description
        Previous value: -"Target tab id (defaults to the active tab)"New value: +"Tab id (default: active tab)"
    • Changednetwork_log3 fields changed
      • changedInput schema / properties / allFrames / description
        Previous value: -"Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)"New value: +"Act on the first match in ANY frame (the element may be in an iframe)"
      • changedInput schema / properties / frameId / description
        Previous value: -"Act inside this frame (ids come from frames_list)"New value: +"Frame id from frames_list"
      • changedInput schema / properties / tabId / description
        Previous value: -"Target tab id (defaults to the active tab)"New value: +"Tab id (default: active tab)"
    • Changedpress2 fields changed
      • changedInput schema / properties / failOnAuthWall / description
        Previous value: -"Fail with [AUTH_REQUIRED] when the page this call lands on is a high-confidence sign-in wall (session expired). Off by default unless the server runs with --fail-on-auth-wall; snapshot still reports the verdict as `authWall` either way."New value: +"Error with [AUTH_REQUIRED] if this lands on a sign-in wall (expired session)"
      • changedInput schema / properties / tabId / description
        Previous value: -"Target tab id (defaults to the active tab)"New value: +"Tab id (default: active tab)"
    • Changedprint_pdf1 field changed
      • changedInput schema / properties / tabId / description
        Previous value: -"Target tab id (defaults to the active tab)"New value: +"Tab id (default: active tab)"
    • Addedprofile_rename
    • Changedread_as_markdown4 fields changed
      • changedInput schema / properties / allFrames / description
        Previous value: -"Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)"New value: +"Act on the first match in ANY frame (the element may be in an iframe)"
      • changedInput schema / properties / frameId / description
        Previous value: -"Act inside this frame (ids come from frames_list)"New value: +"Frame id from frames_list"
      • changedInput schema / properties / maxBytes / description
        Previous value: -"Cap the returned content at this many UTF-8 bytes (default 262144). A truncated result reports truncated/totalBytes/returnedBytes. The full payload is still written to the task's results/ dir."New value: +"Cap returned content at N UTF-8 bytes (default 262144); the full payload still lands in results/"
      • changedInput schema / properties / tabId / description
        Previous value: -"Target tab id (defaults to the active tab)"New value: +"Tab id (default: active tab)"
    • Changedreload2 fields changed
      • changedInput schema / properties / failOnAuthWall / description
        Previous value: -"Fail with [AUTH_REQUIRED] when the page this call lands on is a high-confidence sign-in wall (session expired). Off by default unless the server runs with --fail-on-auth-wall; snapshot still reports the verdict as `authWall` either way."New value: +"Error with [AUTH_REQUIRED] if this lands on a sign-in wall (expired session)"
      • changedInput schema / properties / tabId / description
        Previous value: -"Target tab id (defaults to the active tab)"New value: +"Tab id (default: active tab)"
    • Changedscreenshot5 fields changed
      • changedInput schema / properties / allFrames / description
        Previous value: -"Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)"New value: +"Act on the first match in ANY frame (the element may be in an iframe)"
      • changedInput schema / properties / frameId / description
        Previous value: -"Act inside this frame (ids come from frames_list)"New value: +"Frame id from frames_list"
      • changedInput schema / properties / ref / description
        Previous value: -"Element ref from a prior read (exactly one of selector|ref)"New value: +"Element ref from a snapshot"
      • changedInput schema / properties / selector / description
        Previous value: -"CSS selector (exactly one of selector|ref)"New value: +"CSS selector (or pass ref)"
      • changedInput schema / properties / tabId / description
        Previous value: -"Target tab id (defaults to the active tab)"New value: +"Tab id (default: active tab)"
    • Changedscroll5 fields changed
      • changedInput schema / properties / allFrames / description
        Previous value: -"Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)"New value: +"Act on the first match in ANY frame (the element may be in an iframe)"
      • changedInput schema / properties / frameId / description
        Previous value: -"Act inside this frame (ids come from frames_list)"New value: +"Frame id from frames_list"
      • changedInput schema / properties / ref / description
        Previous value: -"Element ref from a prior read (exactly one of selector|ref)"New value: +"Element ref from a snapshot"
      • changedInput schema / properties / selector / description
        Previous value: -"CSS selector (exactly one of selector|ref)"New value: +"CSS selector (or pass ref)"
      • changedInput schema / properties / tabId / description
        Previous value: -"Target tab id (defaults to the active tab)"New value: +"Tab id (default: active tab)"
    • Changedselect_option10 fields changed
      • changedInput schema / properties / allFrames / description
        Previous value: -"Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)"New value: +"Act on the first match in ANY frame (the element may be in an iframe)"
      • changedInput schema / properties / failOnAuthWall / description
        Previous value: -"Fail with [AUTH_REQUIRED] when the page this call lands on is a high-confidence sign-in wall (session expired). Off by default unless the server runs with --fail-on-auth-wall; snapshot still reports the verdict as `authWall` either way."New value: +"Error with [AUTH_REQUIRED] if this lands on a sign-in wall (expired session)"
      • changedInput schema / properties / frameId / description
        Previous value: -"Act inside this frame (ids come from frames_list)"New value: +"Frame id from frames_list"
      • changedInput schema / properties / name / description
        Previous value: -"Target by accessible name/visible label (pairs with role)"New value: +"Accessible name / visible label (pair with role)"
      • changedInput schema / properties / nth / description
        Previous value: -"Pick the nth (0-based) match when a role+name locator is legitimately ambiguous"New value: +"0-based index when role+name is ambiguous"
      • changedInput schema / properties / ref / description
        Previous value: -"Element ref from a prior read (exactly one of selector|ref)"New value: +"Element ref from a snapshot"
      • changedInput schema / properties / role / description
        Previous value: -"Target by ARIA role (e.g. button, link, textbox) - alternative to selector/ref"New value: +"ARIA role, e.g. button|link|textbox (pair with name)"
      • changedInput schema / properties / selector / description
        Previous value: -"CSS selector (exactly one of selector|ref)"New value: +"CSS selector (or ref, or role+name)"
      • changedInput schema / properties / snapshotAfter / description
        Previous value: -"Return what CHANGED on the page after this action (added/removed/changed elements vs the last snapshot) instead of making you re-read the page"New value: +"Return what CHANGED on the page after this action instead of making you re-read it"
      • changedInput schema / properties / tabId / description
        Previous value: -"Target tab id (defaults to the active tab)"New value: +"Tab id (default: active tab)"
    • Changedsnapshot4 fields changed
      • changedInput schema / properties / allFrames / description
        Previous value: -"Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)"New value: +"Act on the first match in ANY frame (the element may be in an iframe)"
      • changedInput schema / properties / failOnAuthWall / description
        Previous value: -"Fail with [AUTH_REQUIRED] when the page this call lands on is a high-confidence sign-in wall (session expired). Off by default unless the server runs with --fail-on-auth-wall; snapshot still reports the verdict as `authWall` either way."New value: +"Error with [AUTH_REQUIRED] if this lands on a sign-in wall (expired session)"
      • changedInput schema / properties / frameId / description
        Previous value: -"Act inside this frame (ids come from frames_list)"New value: +"Frame id from frames_list"
      • changedInput schema / properties / tabId / description
        Previous value: -"Target tab id (defaults to the active tab)"New value: +"Tab id (default: active tab)"
    • Changedstorage1 field changed
      • changedInput schema / properties / tabId / description
        Previous value: -"Target tab id (defaults to the active tab)"New value: +"Tab id (default: active tab)"
    • Changedtype10 fields changed
      • changedInput schema / properties / allFrames / description
        Previous value: -"Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)"New value: +"Act on the first match in ANY frame (the element may be in an iframe)"
      • changedInput schema / properties / failOnAuthWall / description
        Previous value: -"Fail with [AUTH_REQUIRED] when the page this call lands on is a high-confidence sign-in wall (session expired). Off by default unless the server runs with --fail-on-auth-wall; snapshot still reports the verdict as `authWall` either way."New value: +"Error with [AUTH_REQUIRED] if this lands on a sign-in wall (expired session)"
      • changedInput schema / properties / frameId / description
        Previous value: -"Act inside this frame (ids come from frames_list)"New value: +"Frame id from frames_list"
      • changedInput schema / properties / name / description
        Previous value: -"Target by accessible name/visible label (pairs with role)"New value: +"Accessible name / visible label (pair with role)"
      • changedInput schema / properties / nth / description
        Previous value: -"Pick the nth (0-based) match when a role+name locator is legitimately ambiguous"New value: +"0-based index when role+name is ambiguous"
      • changedInput schema / properties / ref / description
        Previous value: -"Element ref from a prior read (exactly one of selector|ref)"New value: +"Element ref from a snapshot"
      • changedInput schema / properties / role / description
        Previous value: -"Target by ARIA role (e.g. button, link, textbox) - alternative to selector/ref"New value: +"ARIA role, e.g. button|link|textbox (pair with name)"
      • changedInput schema / properties / selector / description
        Previous value: -"CSS selector (exactly one of selector|ref)"New value: +"CSS selector (or ref, or role+name)"
      • changedInput schema / properties / snapshotAfter / description
        Previous value: -"Return what CHANGED on the page after this action (added/removed/changed elements vs the last snapshot) instead of making you re-read the page"New value: +"Return what CHANGED on the page after this action instead of making you re-read it"
      • changedInput schema / properties / tabId / description
        Previous value: -"Target tab id (defaults to the active tab)"New value: +"Tab id (default: active tab)"
    • Changedupload_file3 fields changed
      • changedInput schema / properties / ref / description
        Previous value: -"Element ref from a prior read (exactly one of selector|ref)"New value: +"Element ref from a snapshot"
      • changedInput schema / properties / selector / description
        Previous value: -"CSS selector (exactly one of selector|ref)"New value: +"CSS selector (or pass ref)"
      • changedInput schema / properties / tabId / description
        Previous value: -"Target tab id (defaults to the active tab)"New value: +"Tab id (default: active tab)"
    • Changedwait_for4 fields changed
      • changedInput schema / properties / allFrames / description
        Previous value: -"Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)"New value: +"Act on the first match in ANY frame (the element may be in an iframe)"
      • changedInput schema / properties / failOnAuthWall / description
        Previous value: -"Fail with [AUTH_REQUIRED] when the page this call lands on is a high-confidence sign-in wall (session expired). Off by default unless the server runs with --fail-on-auth-wall; snapshot still reports the verdict as `authWall` either way."New value: +"Error with [AUTH_REQUIRED] if this lands on a sign-in wall (expired session)"
      • changedInput schema / properties / frameId / description
        Previous value: -"Act inside this frame (ids come from frames_list)"New value: +"Frame id from frames_list"
      • changedInput schema / properties / tabId / description
        Previous value: -"Target tab id (defaults to the active tab)"New value: +"Tab id (default: active tab)"
  4. 13 tool updatesv0.9.3
    • Addedauth_check
    • Changedback1 field changed
      • addedInput schema / properties / failOnAuthWall
        Added value: +{
        +  "description": "Fail with [AUTH_REQUIRED] when the page this call lands on is a high-confidence sign-in wall (session expired). Off by default unless the server runs with --fail-on-auth-wall; snapshot still reports the verdict as `authWall` either way.",
        +  "type": "boolean"
        +}
    • Changedclick1 field changed
      • addedInput schema / properties / failOnAuthWall
        Added value: +{
        +  "description": "Fail with [AUTH_REQUIRED] when the page this call lands on is a high-confidence sign-in wall (session expired). Off by default unless the server runs with --fail-on-auth-wall; snapshot still reports the verdict as `authWall` either way.",
        +  "type": "boolean"
        +}
    • Changedfill_form1 field changed
      • addedInput schema / properties / failOnAuthWall
        Added value: +{
        +  "description": "Fail with [AUTH_REQUIRED] when the page this call lands on is a high-confidence sign-in wall (session expired). Off by default unless the server runs with --fail-on-auth-wall; snapshot still reports the verdict as `authWall` either way.",
        +  "type": "boolean"
        +}
    • Changedforward1 field changed
      • addedInput schema / properties / failOnAuthWall
        Added value: +{
        +  "description": "Fail with [AUTH_REQUIRED] when the page this call lands on is a high-confidence sign-in wall (session expired). Off by default unless the server runs with --fail-on-auth-wall; snapshot still reports the verdict as `authWall` either way.",
        +  "type": "boolean"
        +}
    • Changednavigate1 field changed
      • addedInput schema / properties / failOnAuthWall
        Added value: +{
        +  "description": "Fail with [AUTH_REQUIRED] when the page this call lands on is a high-confidence sign-in wall (session expired). Off by default unless the server runs with --fail-on-auth-wall; snapshot still reports the verdict as `authWall` either way.",
        +  "type": "boolean"
        +}
    • Changedpress1 field changed
      • addedInput schema / properties / failOnAuthWall
        Added value: +{
        +  "description": "Fail with [AUTH_REQUIRED] when the page this call lands on is a high-confidence sign-in wall (session expired). Off by default unless the server runs with --fail-on-auth-wall; snapshot still reports the verdict as `authWall` either way.",
        +  "type": "boolean"
        +}
    • Changedreload1 field changed
      • addedInput schema / properties / failOnAuthWall
        Added value: +{
        +  "description": "Fail with [AUTH_REQUIRED] when the page this call lands on is a high-confidence sign-in wall (session expired). Off by default unless the server runs with --fail-on-auth-wall; snapshot still reports the verdict as `authWall` either way.",
        +  "type": "boolean"
        +}
    • Changedscreenshot3 fields changed
      • addedInput schema / properties / format
        Added value: +{
        +  "enum": [
        +    "jpeg",
        +    "png"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / quality
        Added value: +{
        +  "type": "number"
        +}
      • addedInput schema / properties / scale
        Added value: +{
        +  "type": "number"
        +}
    • Changedselect_option1 field changed
      • addedInput schema / properties / failOnAuthWall
        Added value: +{
        +  "description": "Fail with [AUTH_REQUIRED] when the page this call lands on is a high-confidence sign-in wall (session expired). Off by default unless the server runs with --fail-on-auth-wall; snapshot still reports the verdict as `authWall` either way.",
        +  "type": "boolean"
        +}
    • Changedsnapshot1 field changed
      • addedInput schema / properties / failOnAuthWall
        Added value: +{
        +  "description": "Fail with [AUTH_REQUIRED] when the page this call lands on is a high-confidence sign-in wall (session expired). Off by default unless the server runs with --fail-on-auth-wall; snapshot still reports the verdict as `authWall` either way.",
        +  "type": "boolean"
        +}
    • Changedtype1 field changed
      • addedInput schema / properties / failOnAuthWall
        Added value: +{
        +  "description": "Fail with [AUTH_REQUIRED] when the page this call lands on is a high-confidence sign-in wall (session expired). Off by default unless the server runs with --fail-on-auth-wall; snapshot still reports the verdict as `authWall` either way.",
        +  "type": "boolean"
        +}
    • Changedwait_for1 field changed
      • addedInput schema / properties / failOnAuthWall
        Added value: +{
        +  "description": "Fail with [AUTH_REQUIRED] when the page this call lands on is a high-confidence sign-in wall (session expired). Off by default unless the server runs with --fail-on-auth-wall; snapshot still reports the verdict as `authWall` either way.",
        +  "type": "boolean"
        +}
  5. 20 tool updatesv0.7.0
    • Changedbatch1 field changed
      • addedInput schema / properties / maxResultBytes
        Added value: +{
        +  "description": "Total payload budget across all ops (default 1048576). Ops past the budget are replaced by a one-line summary instead of their content, so a 50-op screenshot/get_html batch cannot flood the caller.",
        +  "type": "number"
        +}
    • Changedclick6 fields changed
      • addedInput schema / properties / allFrames
        Added value: +{
        +  "description": "Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / frameId
        Added value: +{
        +  "description": "Act inside this frame (ids come from frames_list)",
        +  "type": "number"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Target by accessible name/visible label (pairs with role)",
        +  "type": "string"
        +}
      • addedInput schema / properties / nth
        Added value: +{
        +  "description": "Pick the nth (0-based) match when a role+name locator is legitimately ambiguous",
        +  "type": "number"
        +}
      • addedInput schema / properties / role
        Added value: +{
        +  "description": "Target by ARIA role (e.g. button, link, textbox) - alternative to selector/ref",
        +  "type": "string"
        +}
      • addedInput schema / properties / snapshotAfter
        Added value: +{
        +  "description": "Return what CHANGED on the page after this action (added/removed/changed elements vs the last snapshot) instead of making you re-read the page",
        +  "type": "boolean"
        +}
    • Addedconsole_logs
    • Addeddialogs
    • Changedeval2 fields changed
      • addedInput schema / properties / allFrames
        Added value: +{
        +  "description": "Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / frameId
        Added value: +{
        +  "description": "Act inside this frame (ids come from frames_list)",
        +  "type": "number"
        +}
    • Changedextract_links2 fields changed
      • addedInput schema / properties / allFrames
        Added value: +{
        +  "description": "Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / frameId
        Added value: +{
        +  "description": "Act inside this frame (ids come from frames_list)",
        +  "type": "number"
        +}
    • Changedfill_form4 fields changed
      • addedInput schema / properties / allFrames
        Added value: +{
        +  "description": "Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)",
        +  "type": "boolean"
        +}
      • removedInput schema / properties / fields / additionalProperties / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "boolean"
        -  }
        -]
      • addedInput schema / properties / fields / additionalProperties / type
        Added value: +[
        +  "string",
        +  "boolean"
        +]
      • addedInput schema / properties / frameId
        Added value: +{
        +  "description": "Act inside this frame (ids come from frames_list)",
        +  "type": "number"
        +}
    • Addedframes_list
    • Changedget_html3 fields changed
      • addedInput schema / properties / allFrames
        Added value: +{
        +  "description": "Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / frameId
        Added value: +{
        +  "description": "Act inside this frame (ids come from frames_list)",
        +  "type": "number"
        +}
      • addedInput schema / properties / maxBytes
        Added value: +{
        +  "description": "Cap the returned content at this many UTF-8 bytes (default 262144). A truncated result reports truncated/totalBytes/returnedBytes. The full payload is still written to the task's results/ dir.",
        +  "type": "number"
        +}
    • Changedget_text3 fields changed
      • addedInput schema / properties / allFrames
        Added value: +{
        +  "description": "Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / frameId
        Added value: +{
        +  "description": "Act inside this frame (ids come from frames_list)",
        +  "type": "number"
        +}
      • addedInput schema / properties / maxBytes
        Added value: +{
        +  "description": "Cap the returned content at this many UTF-8 bytes (default 262144). A truncated result reports truncated/totalBytes/returnedBytes. The full payload is still written to the task's results/ dir.",
        +  "type": "number"
        +}
    • Changedhover6 fields changed
      • addedInput schema / properties / allFrames
        Added value: +{
        +  "description": "Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / frameId
        Added value: +{
        +  "description": "Act inside this frame (ids come from frames_list)",
        +  "type": "number"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Target by accessible name/visible label (pairs with role)",
        +  "type": "string"
        +}
      • addedInput schema / properties / nth
        Added value: +{
        +  "description": "Pick the nth (0-based) match when a role+name locator is legitimately ambiguous",
        +  "type": "number"
        +}
      • addedInput schema / properties / role
        Added value: +{
        +  "description": "Target by ARIA role (e.g. button, link, textbox) - alternative to selector/ref",
        +  "type": "string"
        +}
      • addedInput schema / properties / snapshotAfter
        Added value: +{
        +  "description": "Return what CHANGED on the page after this action (added/removed/changed elements vs the last snapshot) instead of making you re-read the page",
        +  "type": "boolean"
        +}
    • Addednetwork_log
    • Addedprint_pdf
    • Changedread_as_markdown3 fields changed
      • addedInput schema / properties / allFrames
        Added value: +{
        +  "description": "Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / frameId
        Added value: +{
        +  "description": "Act inside this frame (ids come from frames_list)",
        +  "type": "number"
        +}
      • addedInput schema / properties / maxBytes
        Added value: +{
        +  "description": "Cap the returned content at this many UTF-8 bytes (default 262144). A truncated result reports truncated/totalBytes/returnedBytes. The full payload is still written to the task's results/ dir.",
        +  "type": "number"
        +}
    • Changedscreenshot2 fields changed
      • addedInput schema / properties / allFrames
        Added value: +{
        +  "description": "Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / frameId
        Added value: +{
        +  "description": "Act inside this frame (ids come from frames_list)",
        +  "type": "number"
        +}
    • Changedscroll2 fields changed
      • addedInput schema / properties / allFrames
        Added value: +{
        +  "description": "Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / frameId
        Added value: +{
        +  "description": "Act inside this frame (ids come from frames_list)",
        +  "type": "number"
        +}
    • Changedselect_option6 fields changed
      • addedInput schema / properties / allFrames
        Added value: +{
        +  "description": "Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / frameId
        Added value: +{
        +  "description": "Act inside this frame (ids come from frames_list)",
        +  "type": "number"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Target by accessible name/visible label (pairs with role)",
        +  "type": "string"
        +}
      • addedInput schema / properties / nth
        Added value: +{
        +  "description": "Pick the nth (0-based) match when a role+name locator is legitimately ambiguous",
        +  "type": "number"
        +}
      • addedInput schema / properties / role
        Added value: +{
        +  "description": "Target by ARIA role (e.g. button, link, textbox) - alternative to selector/ref",
        +  "type": "string"
        +}
      • addedInput schema / properties / snapshotAfter
        Added value: +{
        +  "description": "Return what CHANGED on the page after this action (added/removed/changed elements vs the last snapshot) instead of making you re-read the page",
        +  "type": "boolean"
        +}
    • Changedsnapshot3 fields changed
      • addedInput schema / properties / allFrames
        Added value: +{
        +  "description": "Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / diff
        Added value: +{
        +  "description": "Return added/removed/changed elements since the previous snapshot of this tab instead of the whole tree",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / frameId
        Added value: +{
        +  "description": "Act inside this frame (ids come from frames_list)",
        +  "type": "number"
        +}
    • Changedtype6 fields changed
      • addedInput schema / properties / allFrames
        Added value: +{
        +  "description": "Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / frameId
        Added value: +{
        +  "description": "Act inside this frame (ids come from frames_list)",
        +  "type": "number"
        +}
      • addedInput schema / properties / name
        Added value: +{
        +  "description": "Target by accessible name/visible label (pairs with role)",
        +  "type": "string"
        +}
      • addedInput schema / properties / nth
        Added value: +{
        +  "description": "Pick the nth (0-based) match when a role+name locator is legitimately ambiguous",
        +  "type": "number"
        +}
      • addedInput schema / properties / role
        Added value: +{
        +  "description": "Target by ARIA role (e.g. button, link, textbox) - alternative to selector/ref",
        +  "type": "string"
        +}
      • addedInput schema / properties / snapshotAfter
        Added value: +{
        +  "description": "Return what CHANGED on the page after this action (added/removed/changed elements vs the last snapshot) instead of making you re-read the page",
        +  "type": "boolean"
        +}
    • Changedwait_for2 fields changed
      • addedInput schema / properties / allFrames
        Added value: +{
        +  "description": "Search every frame of the tab and act on the first that matches - use when a selector should match but does not (the element is in an iframe)",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / frameId
        Added value: +{
        +  "description": "Act inside this frame (ids come from frames_list)",
        +  "type": "number"
        +}
  6. 1 tool updatev0.6.6
    • Changedextract_links2 fields changed
      • addedInput schema / properties / dedupe
        Added value: +{
        +  "type": "boolean"
        +}
      • addedInput schema / properties / limit
        Added value: +{
        +  "type": "number"
        +}
  7. 33 tool updatesv0.6.2
    • First observedback
    • First observedbatch
    • First observedchrome_status
    • First observedclick
    • First observeddownload_file
    • First observedeval
    • First observedextract_links
    • First observedfill_form
    • First observedforward
    • First observedget_cookies
    • First observedget_html
    • First observedget_text
    • First observedhover
    • First observednavigate
    • First observedpress
    • First observedprofile_use
    • First observedread_as_markdown
    • First observedreload
    • First observedscreenshot
    • First observedscroll
    • First observedselect_option
    • First observedsnapshot
    • First observedstorage
    • First observedtab_close
    • First observedtab_new
    • First observedtab_select
    • First observedtabs_list
    • First observedtask_new
    • First observedtask_status
    • First observedtasks_list
    • First observedtype
    • First observedupload_file
    • First observedwait_for

TDQS

B3.2/5.0

Scored across 21 tools

Disambiguation4/5

Each tool has a distinct purpose, but there are clusters that could confuse: proxy_status/chrome_status/task_status all report status, and get_text/get_html/read_as_markdown/snapshot all extract page content. Descriptions do a good job of clarifying the boundaries, so misselection is unlikely but possible.

Naming Consistency3/5

The set mixes several conventions: verb_noun (extract_links, read_as_markdown, get_text), noun_status (chrome_status, task_status), noun_verb (profile_use, task_new, tabs_list), and bare single words (batch, snapshot, storage). Readable but not predictable.

Tool Count4/5

21 tools is on the heavier side but each appears to earn its place across status, profile/task management, extraction, and capture concerns. Reasonable for a full-featured browser automation surface, though slightly bloated.

Completeness3/5

Profile/task lifecycle, content extraction, and capture are well covered, but core interaction tools are absent: there is no navigate, click, type/fill, or scroll, even though snapshot/auth_check explicitly reference targeting by `ref` and acting 'after a navigate'. This is a notable gap for a browser automation server.

Maintenance

ActivityActive
ResponsivenessUnresponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Chrome extension + MCP bridge that gives Claude control over your real browser via CDP, enabling navigation, clicking, typing, scrolling, screenshots, and JS execution with a visible cursor and tab-bring-to-front.
    1
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables AI assistants to control and interact with a Chrome browser via MCP, providing tools for navigation, screenshots, clicking, form filling, content extraction, and tab management.
    -
  • A
    license
    B
    quality
    C
    maintenance
    Enables browser control through your existing signed-in Chrome profile, letting MCP clients like Claude Code manage tabs, navigate, inspect pages, and perform real user interactions via tool calls. Works with any model backend without needing Playwright or a fresh browser profile.
    21
    MIT