Skip to main content
Glama
JustasMonkev

MCP Accessibility Scanner

by JustasMonkev

MCP Accessibility Scanner 🔍

MCP Toplist

Star History

Star History Chart

A powerful Model Context Protocol (MCP) server that provides automated web accessibility scanning and browser automation using Playwright and Axe-core. This server enables LLMs to perform WCAG compliance checks, interact with web pages, manage persistent browser sessions, and generate detailed accessibility reports with visual annotations.

Related MCP server: Accessibility Testing MCP

Features

Accessibility Scanning

✅ Full WCAG 2.0/2.1/2.2 compliance checking (A, AA, AAA levels)
📄 Detailed JSON reports with remediation guidance
🎯 Support for specific violation categories (color contrast, ARIA, forms, keyboard navigation, etc.)

Browser Automation

🖱️ Click, hover, and drag elements using accessibility snapshots
⌨️ Type text and handle keyboard inputs
🔍 Capture page snapshots to discover all interactive elements
📸 Take screenshots and save PDFs
🎯 Support for both element-based and coordinate-based interactions

Advanced Features

📑 Tab management for multi-page workflows
🌐 Monitor console messages and network requests
⏱️ Wait for dynamic content to load
📁 Handle file uploads and browser dialogs
🔄 Navigate through browser history

Installation

You can install the package using any of these methods:

Using npm:

npm install -g mcp-accessibility-scanner

Installation with Docker

A pre-built image is available on Docker Hub. The image includes Chromium and is pre-configured for containerized use — no extra flags needed.

Pull from Docker Hub:

docker pull justasmonkev/mcp-accessibility-scanner

Claude Code

 claude mcp add mcp-accessibility-scanner -s user -- docker run -i --rm justasmonkev/mcp-accessibility-scanner

To persist screenshots and reports on your host, add a volume mount:

claude mcp add mcp-accessibility-scanner -s user \
  -- docker run -i --rm -v /tmp/mcp-output:/app/output justasmonkev/mcp-accessibility-scanner

Without the -v mount, output files only exist inside the container and are lost when it exits.

Docker Compose

docker compose up -d

The Compose configuration publishes the unauthenticated MCP HTTP transport on 127.0.0.1:8931 only. Do not expose this port to untrusted networks.

Build from source

docker build -t mcp-accessibility-scanner .

Docker smoke test

npm run test:docker

Installation in VS Code

Install the Accessibility Scanner in VS Code using the VS Code CLI:

For VS Code:

code --add-mcp '{"name":"accessibility-scanner","command":"npx","args":["mcp-accessibility-scanner"]}'

For VS Code Insiders:

code-insiders --add-mcp '{"name":"accessibility-scanner","command":"npx","args":["mcp-accessibility-scanner"]}'

CLI Modes

The scanner can run in two modes depending on how you use it.

MCP server (default, no subcommand)

When launched without a subcommand, the process starts an MCP server that communicates over stdio. This is the mode used by MCP clients such as Claude Desktop, VS Code, and Claude Code -- you should never need to run it by hand.

npx mcp-accessibility-scanner            # starts the MCP server (stdio)

All of the MCP client configuration examples in this README already use this default mode.

Interactive REPL (interactive subcommand)

For manual terminal use, the interactive subcommand starts a readline REPL where you can call any tool directly:

$ npx mcp-accessibility-scanner interactive
Interactive mode. Type "<tool-name> <json>" to call a tool. Ctrl+D to exit.
> browser_navigate {"url": "https://example.com"}
> scan_page {"violationsTag": ["wcag21aa"]}
> audit_keyboard {"maxTabs": 30}
> audit_screen_reader {}

Each line is <tool-name> <json-arguments>. Omit the JSON to pass {}. Global browser connection flags still apply here, for example npx mcp-accessibility-scanner --headless interactive. Use --mobile or PLAYWRIGHT_MCP_MOBILE=1 to emulate a generic mobile device (Pixel 10 for Chromium, iPhone 17 for WebKit). It cannot be combined with --device, CDP attach/launch modes, remote browser endpoints, or --extension.

Browser extension mode

Use --extension to connect through the current Playwright Extension, which must support extension protocol v2.

npx mcp-accessibility-scanner --extension

Set PLAYWRIGHT_MCP_EXTENSION_TOKEN to the token shown by the extension to bypass the connection approval dialog. The relay's CDP WebSocket endpoint always requires a separate random token, generated per relay and appended automatically for the server's own connection. This CDP token is never passed in Chrome's launch arguments or extension URL; the extension approval token cannot authenticate a CDP client. Token-bypass connections are not background-safe: Chrome focuses the connection tab and window, and client-created tabs remain open after disconnect (upstream limitation). With a token, the extension must connect and finish setup within 30 seconds after the connection page opens. Failed attempts release the relay so the next tool call can retry. Without a token, manual approval waits until you approve or cancel the call. When --user-data-dir contains multiple Chrome profiles, the profile with the extension installed is selected automatically, preferring Chrome's last-used profile.

Discovering available tools (list-tools subcommand)

To print every tool name and its description:

npx mcp-accessibility-scanner list-tools

Note: Tool names like browser_navigate and scan_page are MCP tool identifiers (and REPL commands in interactive mode). They are not shell subcommands -- you cannot run npx mcp-accessibility-scanner browser_navigate.

Configuration

Here's the Claude Desktop configuration:

{
  "mcpServers": {
    "accessibility-scanner": {
      "command": "npx",
      "args": ["-y", "mcp-accessibility-scanner"]
    }
  }
}

Advanced Configuration

You can pass a configuration file to customize Playwright behavior:

{
  "mcpServers": {
    "accessibility-scanner": {
      "command": "npx",
      "args": ["-y", "mcp-accessibility-scanner", "--config", "/path/to/config.json"]
    }
  }
}

Configuration Options

Create a config.json file with the following options:

{
  "browser": {
    "browserName": "chromium",
    "launchOptions": {
      "headless": true,
      "channel": "chrome"
    },
    "cdpLaunch": {
      "command": "open",
      "args": ["-a", "Slack", "--args", "--remote-debugging-port={port}"],
      "startupTimeoutMs": 30000
    }
  },
  "timeouts": {
    "navigationTimeout": 60000,
    "defaultTimeout": 5000,
    "settle": 500
  },
  "network": {
    "allowedOrigins": ["example.com", "trusted-site.com"],
    "blockedOrigins": ["ads.example.com"]
  },
  "snapshot": {
    "boxes": true
  }
}

Available Options:

  • browser.browserName: Browser to use (chromium, firefox, webkit)

  • browser.allowedUploadDirs: Restrict files sent by browser_file_upload and browser_drop to regular files inside these directories, including resolved symlink targets. Restricted uploads and drops use a checked file handle and accept up to 50 MiB total per call. Unset allows any path; [] denies all file uploads and drops (text-only drops still work). Blank list entries are rejected. CLI: --allowed-upload-dirs (semicolon-separated; "" denies all), env: PLAYWRIGHT_MCP_ALLOWED_UPLOAD_DIRS (empty string denies all).

    The list must be an array, not null. Roots must exist at startup: their canonical paths are resolved once and retained for the server's lifetime, so retargeting a configured symlink does not grant access to a new tree. Non-empty upload allowlists require macOS or Linux with /proc/self/fd available. macOS blocks ancestor symlinks during the file open; Linux checks the opened descriptor's path. Other platforms reject restricted file uploads and drops rather than rely on race-prone pathname checks. Unrestricted uploads, deny-all lists, and text-only drops keep working on all platforms.

  • browser.launchOptions.headless: Run browser in headless mode (default: true on Linux without display, false otherwise)

  • browser.launchOptions.channel: Browser channel (chrome, chrome-beta, msedge, etc.)

  • browser.launchOptions.chromiumSandbox: Defaults to false for downloaded Chromium builds on Linux because they lack the setuid sandbox helper, and true otherwise. Remote and VS Code endpoints choose on the remote host. An explicit config or PLAYWRIGHT_MCP_SANDBOX value wins; --no-sandbox always disables it.

  • browser.cdpEndpoint: Attach to an already-running Chromium-family app with CDP enabled

  • browser.cdpHeaders: Map of HTTP headers to send with the CDP connect request, e.g. { "Authorization": "Bearer <token>" }, for endpoints that require header-based authentication

  • browser.cdpTimeout: Maximum time in milliseconds to wait when connecting to the CDP endpoint (default: 30000)

  • browser.cdpLaunch: Launch a Chromium-family desktop app with CDP enabled, wait for the endpoint, and manage the child process lifecycle

  • CDP attach modes preserve the target browser's existing default-context settings instead of applying Playwright's defaults.

  • browser.contextOptions.storageState: Start each session from a recorded Playwright storage state; applied in every mode except --extension (fresh contexts receive it at creation, reused contexts via setStorageState()). Sessions that share one reused context (non-isolated CDP modes) get the state applied once per context — a session joining a live context inherits its current state, not a fresh copy of the file; see Auditing pages behind a login

  • timeouts.navigationTimeout: Maximum time for page navigation in milliseconds (default: 60000)

  • timeouts.defaultTimeout: Default timeout for Playwright operations in milliseconds (default: 5000)

  • timeouts.settle: How long to wait after every action before responding (default: 500). An action that finishes quietly is first watched for up to 100ms (or the settle delay, whichever is shorter) so scheduled network work can still be awaited before the settle delay.

  • network.allowedOrigins: List of origins to allow (blocks all others if specified)

  • network.blockedOrigins: List of origins to block

  • snapshot.boxes: Include each element's viewport-relative bounding box as [box=x,y,width,height] in snapshots (default: false; CLI: --snapshot-boxes, env: PLAYWRIGHT_MCP_SNAPSHOT_BOXES=1)

  • server.authToken: When set, Streamable HTTP requests (--port) require Authorization: Bearer <token> or return 401 (env: PLAYWRIGHT_MCP_AUTH_TOKEN). Blank or malformed tokens fail at startup. The scheme is case-insensitive; the token is exact. Bearer auth does not encrypt traffic: authenticated listeners must bind to loopback, such as --host 127.0.0.1; use a TLS reverse proxy for remote access. The printed client config includes a header placeholder to replace locally, without logging the secret. Unset keeps unauthenticated access.

  • outputDir: Directory for output files — reports, screenshots, traces, and session logs (CLI: --output-dir, env: PLAYWRIGHT_MCP_OUTPUT_DIR). Defaults to a fresh directory under the system temp folder, resolved once per server run so all of a run's artifacts land together. The output location is always server configuration; the deprecated MCP roots capability (client workspace folders) is no longer consulted.

CLI equivalents are also available: --cdp-launch-command, --cdp-launch-args, --cdp-launch-cwd, --cdp-launch-port, --cdp-launch-startup-timeout, --cdp-endpoint, --cdp-header (repeat for multiple headers, e.g. --cdp-header "Authorization: Bearer <token>"), and --cdp-timeout. The CDP headers and timeout can also be set via the PLAYWRIGHT_MCP_CDP_HEADERS (one Name: Value entry per line) and PLAYWRIGHT_MCP_CDP_TIMEOUT environment variables.

For remote HTTP access, configure the TLS reverse proxy explicitly. For example, with the MCP server bound using --host 127.0.0.1 --port 8931 and PLAYWRIGHT_MCP_AUTH_TOKEN set:

  • Accept only your configured public hostname over HTTPS and forward /mcp to http://127.0.0.1:8931/mcp.

  • Set the upstream Host header to 127.0.0.1:8931, not the public hostname. Forward the client's Authorization header unchanged; do not inject a shared token for unauthenticated clients.

  • Before removing Origin, reject any non-empty value outside your explicit trusted HTTPS origin list (for example, https://mcp.example.com). Allow absent Origin for non-browser clients. Then remove Origin upstream, or rewrite it to http://127.0.0.1:8931. Never strip arbitrary origins without checking them first.

  • Disable response buffering for SSE streams. Browser clients on a different origin also need a narrowly scoped CORS policy at the proxy.

The server does not trust Forwarded or X-Forwarded-* to bypass its checks. Preserving the public Host or HTTPS Origin upstream returns 403, even with a valid bearer token.

Caller-supplied screenshot, PDF, scan-page-matrix, and audit report filenames use a no-clobber policy: an existing file causes the tool call to fail instead of being overwritten. Windows-reserved basenames and names ending in a dot or space are rejected on every platform so configured names behave consistently across hosts.

Use --timeout-settle or PLAYWRIGHT_MCP_TIMEOUT_SETTLE to override the post-action settle delay. It applies after every action so delayed DOM-only updates are included in the response; a short observation window also catches scheduled requests and waits for them before that delay.

The VS Code browser_connect tool accepts only playwright or playwright-core libraries and loopback WebSocket URLs. Set PLAYWRIGHT_MCP_VSCODE_ALLOW_REMOTE=1 to allow remote endpoints, which must use wss:. URL userinfo credentials are rejected.

HTTP Heartbeat

When the server runs with --port, it sends MCP heartbeat pings after a Streamable HTTP client opens the optional event stream. POST-only clients stay connected without heartbeat because server-initiated requests cannot reach them. Set PLAYWRIGHT_MCP_PING_TIMEOUT_MS to override the default 5000 ms timeout, or to 0 or any negative value to disable heartbeat pings. A client that answers ping with a JSON-RPC "method not found" error is treated as alive: the server stops heartbeating that session instead of closing it. Only an unanswered ping (timeout) or a transport failure closes the session.

Clients without the initialize handshake

Clients on the MCP 2026-07-28 revision no longer send the initialize handshake. With --port, requests carrying the revision's per-request _meta envelope are served natively on the 2026-07-28 protocol: server/discover is answered (so clients negotiating with versionNegotiation: 'auto' or a 2026-07-28 pin connect directly), results carry resultType and the SEP-2549 cache fields — the tool list is advertised as cacheable for one hour with cacheScope: "private" — and the SEP-2243 standard headers (MCP-Protocol-Version, Mcp-Method, Mcp-Name) are validated against the request body. Older handshake-free clients (2025-era requests without the envelope) are served statelessly as before. In both cases requests receive no heartbeat pings, and in the modes where the server creates browser contexts itself each request runs against a fresh default browser session: with the default persistent profile the per-request default context runs in its own disposable profile (like an explicit browser session), so parallel handshake-free requests do not contend for the stable profile — and the stable profile's sign-in state is not visible to them — while --isolated, remote endpoints and isolated CDP modes mint a fresh context per request anyway. Modes that reuse one live browser context are the exception: --extension (and a browser_connect or VS Code session switched to a connected-browser provider) and CDP attach without --isolated serve every handshake-free request from the same shared context, so its tabs, cookies and storage persist across requests — the same sharing that makes these modes refuse browser_session_open (in --vscode serving the session tools are the exception: they are host-scoped and keep running against the default provider even while switched — see Browser Session Tools). With a pinned --cdp-launch-port, only one launched application can be served at a time, so a second handshake-free request arriving while another request's browser context is still live is rejected with a clear error instead of silently attaching to the first request's application. With --user-data-dir, each handshake-free request launches a browser in the one configured profile: the profile's state persists across requests, and parallel requests contend for its browser lock and can fail with "Browser is already in use". Elsewhere, browser state that must persist across handshake-free requests belongs in an explicit browser session — a browserSessionId handle minted by browser_session_open in one request resolves in later ones (see Browser Session Tools). Clients that do send initialize keep the classic Mcp-Session-Id session behavior unchanged. When several such stateful clients are connected at once in the default persistent-profile mode, the first client's default context holds the stable profile — concurrent clients' default contexts run in their own disposable profiles (without the stable profile's sign-in state) until it is freed, instead of failing with "Browser is already in use".

Auditing pages behind a login

Most real audits target pages that only exist for a signed-in user. There are two ways to get there.

Interactive route (no setup)

Every tool shares one browser context, and audit_site crawls in a temporary tab of that same context, so cookies and local storage created while you drive the browser are already available to the crawl:

1. browser_navigate to the login page
2. browser_fill_form / browser_click to sign in
3. browser_navigate to the first page you want audited
4. audit_site — the crawl inherits the session you just created

This works out of the box in every mode, including the default persistent-profile mode. With the default profile the session also survives across server restarts, so you usually only sign in once. The default profile is keyed to the server's working directory, so each workspace's server keeps its own sign-in state — servers launched for different workspaces neither share cookies nor contend for the same profile.

Storage state route (repeatable, CI-friendly)

Record a session once with Playwright's codegen, then hand the file to the server:

npx playwright@1.63.0 codegen --save-storage=auth.json https://example.com/login

Sign in in the opened browser, then close it — auth.json now holds the cookies and local storage.

Pass it to the server with the CLI flag, the environment variable, or the config file:

npx mcp-accessibility-scanner --isolated --storage-state ./auth.json
PLAYWRIGHT_MCP_ISOLATED=true PLAYWRIGHT_MCP_STORAGE_STATE=./auth.json npx mcp-accessibility-scanner
{
  "browser": {
    "isolated": true,
    "contextOptions": {
      "storageState": "./auth.json"
    }
  }
}

Every supported mode handles the state — by applying it or refusing it.

  • Fresh-context modes (--isolated, the remote-endpoint mode, or either CDP mode combined with --isolated): the context is created with the storage state directly.

  • Default persistent-profile mode with --storage-state: the session runs in a fresh, disposable profile — unique to that session and removed when it closes — built from the state, so the recorded state is provably the only session data (without --storage-state the regular persistent profile is used and survives restarts, as before). Any page the launch opened (for example from a URL in browser.launchOptions.args) is parked on a blank replacement before the state lands, then the replacement is navigated to the same URL, so a still-running anonymous page cannot overwrite the recorded identity and a scan never reads its DOM. This also means --storage-state cannot be combined with --user-data-dir (a user-supplied profile carries its own session and will not be wiped; the server refuses the combination).

  • CDP modes without --isolated: the state is installed into the browser's existing context with Playwright's setStorageState(). Cookies are fully reset; origin storage (localStorage/IndexedDB) is reset for the origins recorded in the state plus any origins the Playwright connection has already seen — including pages open in the attached browser at connect time, whose storage can therefore be cleared even when the state omits them. Only origins from the profile's earlier history that this connection never saw survive untouched — cut in both directions, so treat an attached browser's storage as neither fully preserved nor fully reset, and add --isolated when you need a clean, fully-defined session. Pages already open in the attached browser are replaced with fresh tabs navigated to the same URLs so a scan never sees the previous identity's UI — and the old pages close before the state is installed, because a still-running page could otherwise persist the previous identity back into the freshly applied cookies or localStorage, which no later tab replacement could undo. A fresh tab also starts with empty per-tab sessionStorage (which sits outside Playwright storage states and would survive an in-place reload, where the old page's own scripts could even write the previous identity back between a clear and the reload), a replacement that fails to load is left blank or closed rather than left on a stale document, and these navigations run under a configured --allowed-origins/--blocked-origins policy just like every later navigation. The state is applied once per shared context: concurrent MCP sessions attached without --isolated share the browser's context, so a session joining while another is active inherits that context's live state (including anything the first session changed or cleared) rather than a fresh copy of the recorded file — add --isolated when every session must start from the recorded baseline.

  • --extension (with or without --isolated) is the one exception: it works through the browser you are already running, where wiping cookies to install a recorded state is not an acceptable side effect, so the server refuses to start rather than doing that silently. There, sign in interactively instead — the persistent profile also keeps the session across restarts.

Keep the crawl from destroying its own session

audit_site excludes logout|signout by default, which is not enough for most applications. Add anything else that ends or changes the session before you start the crawl:

{
  "excludePathPatterns": ["logout|signout", "account/(close|delete)", "sessions/revoke", "/switch-(locale|account|org)"]
}

Note that excludePathPatterns replaces the default rather than extending it, so repeat logout|signout in your list.

If a session cookie disappears anyway, audit_site says so instead of reporting a confident, wrong audit: the result starts with a WARNING: cookie(s) … disappeared while loading <url> line, and both the JSON report and the structured content carry a sessionLosses list naming, for each lost cookie, the page that dropped it — the page reached after any redirect, and reported even when that page failed to finish loading. If one of the lost cookies was the session, every page scanned after that point was audited as a signed-out user — exclude the offending URL, sign in again, and re-run.

The check compares which cookies the crawled URLs carry, not their values, so a rotating CSRF token never reads as a lost session. A cookie the browser deleted at its own stated expiry is ignored for the same reason — Cloudflare's __cf_bm lives 30 minutes and would otherwise warn on any longer crawl. Beyond that no attempt is made to tell an authentication cookie from any other: nothing in a cookie marks it as one, so any cookie the crawl started with and later lost is reported. Monitoring does not stop at the first loss — each cookie is reported once, at the URL where it vanished, so an analytics cookie expiring early cannot mask the session cookie being dropped later. URLs discovered mid-crawl join the cookie tracking before they are visited, so a session cookie scoped to a path below the start URL (say /app) is watched too.

Available Tools

The MCP server provides comprehensive browser automation and accessibility scanning tools:

Core Accessibility Tool

scan_page

Performs a comprehensive accessibility scan on the current page using Axe-core.

Parameters:

  • violationsTag: Array of WCAG/violation tags to check

  • includeIncomplete (default true): also report Axe "incomplete" results

  • maxNodesPerViolation (default 10): cap on nodes reported per rule

  • includeSelectors / excludeSelectors: CSS selectors that scope the scan

  • withRules / disableRules: Axe rule ids that narrow which rules run

  • annotateScreenshot (default false): capture an annotated screenshot of the violations

Annotated screenshots: When annotateScreenshot is true, each violating element is outlined and labelled with the rule ids it failed, a full-page PNG is written to the MCP output directory (scan-page-annotated-{timestamp}-{token}.png) and returned as a resource link, and the markers are then removed so the page is left exactly as it was. The markers are drawn in an out-of-flow overlay clipped to each element's own box, so they never reflow the page. The overlay uses a fresh id per scan, is placed in the browser's top layer so it stays visible over an open dialog, popover or fullscreen element, and compensates for a CSS zoom or a scaled ancestor so markers line up with what is rendered. An element that fails several rules gets one box listing every rule id, and elements inside open shadow roots are marked by walking the shadow path Axe reports. Running animations are paused before the elements are measured and resumed after the capture, so a moving target keeps its marker. The markers themselves live in a shadow root under an overlay whose own styles are !important, so page CSS cannot restyle or hide what the report counts, and each rule label sits outside the clipped box so it stays readable on an element smaller than its own label. At most 50 elements are annotated per scan. The result text always reports how many nodes were marked out of the total, plus how many were left out because they exceeded the limit, were hidden, zero-size or off-canvas (a full-page screenshot is clipped to the document box), or were inside an iframe (cross-frame selectors cannot be resolved from the top document).

Supported Violation Tags:

  • WCAG standards (in the default set): wcag2a, wcag2aa, wcag2aaa, wcag21a, wcag21aa, wcag21aaa, wcag22a, wcag22aa, wcag22aaa

  • Section 508 (in the default set): section508

  • Categories (opt-in): cat.aria, cat.color, cat.forms, cat.keyboard, cat.language, cat.name-role-value, cat.parsing, cat.semantics, cat.sensory-and-visual-cues, cat.structure, cat.tables, cat.text-alternatives, cat.time-and-media

  • Non-conformance tags (opt-in): best-practice, experimental (see the caveat below -- a few experimental rules also carry a WCAG tag and run by default)

The default set is the WCAG and Section 508 tags only, so a default report means "this fails a conformance criterion". Category tags are opt-in for that reason: Axe matches requested tags with OR, so asking for cat.keyboard also pulls in best-practice rules such as region and skip-link that carry both tags. No live conformance rule is lost by leaving them out: the only rules reachable only through a cat.* tag are duplicate-id and duplicate-id-active, which Axe marks deprecated because WCAG removed SC 4.1.1. Add best-practice (landmark structure, heading order, tabindex hygiene) or a cat.* tag when you want that broader review.

The same OR semantics apply to experimental, with one deliberate exception: five experimental rules -- css-orientation-lock (SC 1.3.4), label-content-name-mismatch (SC 2.5.3), p-as-heading, table-fake-caption and td-has-header (SC 1.3.1) -- also carry a wcag* tag and so run in the default set. In Axe, experimental describes how settled the heuristic is, not whether the criterion is real, so these are kept rather than filtered out. Adding the experimental tag pulls in the remaining experimental rules, which have no conformance tag of their own.

Scan scoping: scan_page, audit_site, and scan_page_matrix accept includeSelectors and excludeSelectors to limit what Axe looks at. Use includeSelectors to audit one component (["#checkout-form"]) and excludeSelectors to drop third-party noise that pollutes every report (["#cookie-banner", "iframe.intercom-frame"]). Exclusions are applied after inclusions, so you can carve a widget out of an included subtree.

Selectors are resolved before the scan runs:

  • Syntactically invalid CSS fails the scan, naming the selector.

  • An includeSelectors entry that matches nothing fails the scan. Axe on its own would accept a partly-matching include set and quietly scan less than you asked for, so the scanner refuses rather than returning a clean-looking report with half the scope missing.

  • An excludeSelectors entry that matches nothing is a no-op, not an error -- a crawl legitimately visits pages that lack the excluded widget.

In audit_site, selectors apply to every crawled page, so an includeSelectors value that is absent from a given page marks that page as errored in the report while the crawl continues. Link discovery runs before the scan, so pages reachable only through an errored page are still crawled.

Rule-level control: scan_page, audit_site, and scan_page_matrix accept withRules and disableRules to pick individual Axe rules instead of whole tag sets. Use withRules to re-check one rule after a fix (["color-contrast"]) and disableRules to mute a rule you have already triaged (["region"]). Rule ids are the ones Axe reports (image-alt, color-contrast, ...); see the Deque rule reference.

  • withRules overrides violationsTag. Axe can run either a rule list or a tag list, never both, so when withRules is set the tags are ignored entirely -- withRules: ["image-alt"] runs exactly that one rule regardless of violationsTag. Rule ids are the more specific request, so they win.

  • disableRules subtracts from whatever is selected. It applies to violationsTag and withRules alike. (Axe itself ignores disabled rules once you give it an explicit rule list; the scanner subtracts them up front so the two options mean the same thing together as apart.) Disabling every rule in withRules is an error rather than an empty scan.

  • An explicitly empty withRules is an error too. withRules: [] selects no rules, and silently falling back to the tag set would run a different scan than the one requested — omit the option to scan by tags instead. Clients that build the list dynamically should drop the key when the list comes out empty.

  • Unknown rule ids fail the scan, naming the id. Both options are checked against Axe's rule catalogue before the browser is touched, so a typo is reported as Unknown Axe rule id(s) in withRules: image-altt rather than surfacing later as an frame.evaluate failure from inside the page. Rule ids apply to a whole run, so audit_site and scan_page_matrix check them once before they touch the page -- a bad id fails the call outright instead of crawling every URL, or reloading and re-emulating the page, before rejecting the argument.

audit_site and scan_page_matrix record both values in their JSON report metadata, so a stored report can be told apart from a full scan.

Incomplete ("needs review") results: Axe returns incomplete for checks it cannot decide on its own -- contrast over a background image or gradient, ambiguous labels, elements it could not fully evaluate. scan_page, audit_site, and scan_page_matrix report these in a section separate from violations so you can resolve them by inspecting the page (screenshot, snapshot, browser_evaluate). Set includeIncomplete: false to suppress them.

Frames that could not be scanned: Axe is installed into every frame of the page before the scan runs. A frame that navigates mid-injection, or whose renderer does not answer within a second, is left out -- and its contents then contribute no findings. Rather than let that pass as a clean result, all three scan tools print a WARNING: Axe could not be installed in N frame(s) block listing the frame URLs, and audit_site and scan_page_matrix also record them per page and per variant in their JSON reports (unscannedFrames) and in structuredContent. A frame that was still loading usually succeeds on a re-run; one that fails consistently has to be audited on its own.

A nested frame is reported when any frame above it went unscanned, even if its own injection succeeded: Axe reaches a nested document only by relaying through the frames above it, so an outer frame without Axe takes everything below it out of the scan.

A frame you scoped out yourself is not reported: with excludeSelectors: ["iframe.intercom-frame"] that widget failing to load is the outcome you asked for, not a gap. Scope is resolved through the whole frame chain and across shadow boundaries, so an includeSelectors entry naming an ancestor still covers frames nested several levels below it or inside a shadow root, and excluding an outer frame or a shadow host silences everything inside it. Anything the check cannot resolve is reported rather than hidden.

Audit Tools

audit_site

Crawls and scans multiple internal pages, then aggregates violations across the site.

  • Default strategy: link-based BFS from the current URL

  • Supports links, nav, sitemap, and provided URL strategies

  • Sitemap URLs and every redirect must pass the server network policy and crawl scope. Fetches run on the MCP host, use HTTP(S) without browser cookies or auth headers, and have a 15-second total timeout, 20-redirect cap, and 10 MiB response limit. Browser proxy settings, browser.remoteEndpoint, browser.cdpEndpoint (including loopback endpoints, which may tunnel to remote browsers), and switched browser_connect providers are rejected for this strategy; use provided URLs in these modes. Sitemap TLS certificates must be valid even when browser HTTPS errors are ignored.

  • Always writes a JSON report (default filename: audit-site-{timestamp}-{token}.json)

  • Warns and records sessionLosses if the crawl loses cookies it started with — see Auditing pages behind a login

Example flow:

1. Navigate to your site homepage with browser_navigate
2. Run audit_site with maxPages: 25 and maxDepth: 2
3. Review the report path returned by the tool (written to the MCP output directory)

scan_page_matrix

Runs Axe scans on the same page across viewport/media/zoom variants and compares deltas against baseline.

  • Default variants: baseline, mobile, desktop, forced-colors, reduced-motion, zoom-200

  • Supports custom variants and optional reload between variants

  • Always writes a JSON report (default filename: scan-matrix-{timestamp}-{token}.json)

  • JSON report and structured result schema v2 set baseline deltas to null when either scan left frames unscanned, because their coverage is not comparable

Example flow:

1. Navigate to a page state you want to validate
2. Run scan_page_matrix with defaults (or provide custom variants)
3. Review per-variant deltas and open the generated JSON report path

audit_keyboard

Audits real keyboard focus behavior by pressing Tab (and optional Shift+Tab) with practical heuristics.

  • Checks skip links, focus visibility, focus jumps, and possible focus traps

  • Checks target size against WCAG 2.2 SC 2.5.8 (checkTargetSize, default on)

  • Checks that focus is not entirely obscured, WCAG 2.2 SC 2.4.11 (checkFocusObscured, default on)

  • Optional issue screenshots (screenshotOnIssue)

  • Always writes a JSON report (default filename: audit-keyboard-{timestamp}-{token}.json)

Limits of the WCAG 2.2 checks — these are heuristics, not a conformance verdict:

  • Target size only inspects elements the tab order actually reaches, so pointer-only targets are never measured.

  • Of the SC 2.5.8 exceptions, only spacing (a 24px-diameter circle centered on the target must reach neither another target's box nor another undersized target's circle) and inline (an inline-level target — inline, inline-block, inline-flex, … — inside surrounding sentence text, found by walking out through inline wrappers such as <strong> to the containing block) are evaluated. The user agent control, essential, and equivalent exceptions cannot be detected from the DOM, so a target relying on one of them is still reported and needs manual triage.

  • Spacing neighbours use the same pointer-target rule as the focused element, so rendered :disabled controls are not counted as neighbours, and contenteditable regions are counted as targets on both sides.

  • Target size uses the element's bounding box, so an inline target wrapped over several lines is measured as one union box rather than per line, and a target whose visible area is cut down by an overflow or clip-path ancestor is measured at its full unclipped size.

  • SC 2.4.11 is the Minimum (AA) level: a focused element is only reported when every sampled point of its box is covered by other content. Partially covered focus passes here, and the stricter SC 2.4.12 (AAA) is not checked. It applies to every focus stop with a rendered box, including elements that are not pointer targets such as iframes.

  • Coverage is measured by hit-testing sample points and then checking that the element hit actually paints (visible, non-zero opacity all the way up to the first wrapper shared with the focused element, non-transparent background or background image). A transparent click-catching overlay therefore does not count as obscuration, but a covering layer with pointer-events: none is never returned by hit testing and is missed. Semi-transparent overlays that still leave content legible are reported.

Example flow:

1. Navigate to the target page and let it fully load
2. Run audit_keyboard with maxTabs: 50
3. Review focus findings and open the generated JSON report path

audit_screen_reader

Audits what a screen reader actually announces, using the browser's own accessibility tree (page.ariaSnapshot) plus element geometry. No screen reader is installed or driven; this is a static reading of the exposed tree.

Checks (checkNames)

  • missing-accessible-name: controls and images exposed with no accessible name (WCAG 4.1.2)

  • uninformative-accessible-name: names such as "click here", "read more", "image" that mean nothing out of context (WCAG 2.4.4)

  • filename-as-accessible-name: image alt text that is a file name, e.g. IMG_1234.jpg, DSC00123 (WCAG 1.1.1). Only images are checked: a link or button legitimately named after the file it downloads (logo.png) is not a defect.

  • label-in-name-mismatch: the accessible name does not contain the visible label, which breaks voice control (WCAG 2.5.3). The visible label of <input type="submit|button|reset"> is read from its value, and a web component's label is read from its open shadow root.

  • duplicate-accessible-name: sibling links with the same name that lead to different URLs (WCAG 2.4.4)

Check (checkReadingOrder)

  • reading-order-mismatch: accessibility tree order (what is read) versus visual position (WCAG 1.3.2), i.e. order, flex-direction: row-reverse, absolute positioning

What it deliberately does not detect

  • Reading order is only compared between siblings that form a single row or a single column. Genuine two-dimensional layouts (grid, CSS multi-column, wrapped flex) have no single correct linear order and are skipped rather than guessed.

  • Elements are excluded from the reading-order comparison when they render no text, are aria-hidden, floated, position: fixed, off-canvas, or clipped to 1px, because their visual position is decoupled from source order by design. Tolerance: two boxes count as swapped only when they are fully separated along the compared axis (1px), and right-to-left containers are compared right-to-left.

  • Duplicate names are only reported when the destinations differ and are observable, which today means resolved link URLs (/help and https://site/help are the same destination). Two Save submit buttons in one form are never called ambiguous, because nothing in the exposed tree says whether they do different things.

  • Only elements the AI snapshot gives a ref are analyzed, and Playwright refs the elements that are visible and receive pointer events. A control that is announced but not interactable (pointer-events: none, some off-canvas widgets) is therefore skipped: without a ref it cannot be measured, so neither its aria-hidden state nor a selector to fix it can be established, and reporting it would mostly surface decorative aria-hidden icons.

  • Heading levels and landmark structure are not checked; axe already reports those (heading-order, region, landmark-one-main), so use scan_page for them.

  • Findings for names overlap with axe rules such as link-name, button-name and image-alt; this tool adds the quality checks (generic names, file names, label-in-name, duplicates) that axe cannot make.

  • It reports the page as currently rendered. Content behind a collapsed panel or another viewport is judged in that state.

How names are measured: the AI snapshot omits a name that a control's rendered children carry (<a><strong>Docs</strong></a>, a button whose label sits in a <span>), so the audit installs its own copy of axe-core in each frame it measures and takes the accessible name axe computes there. The page's own window.axe, if any, is left as it was. Installing is bounded (10 s for the main frame, 1 s per child frame). A frame that refuses the copy (a blocking CSP, a page that removes it) is measured without names. The result says so: a WARNING: accessible names could not be measured for N of these line, elementsWithoutMeasuredName in the structured summary, and elements.unmeasuredNames in the JSON report. In those frames the snapshot's own names stand, so a missing-accessible-name finding for a control named only through its children may be a false positive; treat the name findings of a run with a non-zero count as partial and confirm them by hand. A frame that times out or stops answering is not evaluated by any check: its elements are counted as unresolved (with their own warning), and if that leaves nothing evaluated the audit fails rather than report a clean page. Every read of a frame is bounded by the same budgets (10 s main frame, 1 s child frame; the lookup that tells which frame owns an element gets the larger one), so a frame that stops answering cannot hold the audit open. At most four frame operations per page stay in flight across overlapping audits; if four timed-out operations are still running, no more frame work starts and the result says where measurement stopped.

Bounds: maxElements (default 400) caps how many screen-reader-reachable accessibility tree elements are analyzed. The snapshot also refs aria-hidden subtrees, which no check reports, so measuring continues past them until the budget is filled with reachable elements (up to a hard ceiling of twice maxElements measured, so a page built mostly of hidden refs stays bounded). maxFindingsPerCheck (default 20) caps the findings listed per check. Both truncations are stated in the summary and the JSON report, and the full counts are always reported. Always writes a JSON report (default filename: audit-screen-reader-{timestamp}-{token}.json).

Example flow:

1. Navigate to the target page and let it fully load
2. Run audit_screen_reader (optionally raise maxElements for a large page)
3. Fix the reported elements by ref, then re-run to confirm

Navigation Tools

browser_navigate

Navigate to a URL.

  • Parameters: url (string)

  • Non-2xx main-document responses are shown as an HTTP status line in page state.

browser_navigate_back

Go back to the previous page.

browser_navigation_timeout

Set default navigation timeout for existing tabs.

  • Parameters: timeout (in ms; 30000-300000)

browser_default_timeout

Set default operation timeout for existing tabs.

  • Parameters: timeout (in ms; 30000-300000)

Page Interaction Tools

browser_snapshot

Capture accessibility snapshot of the current page (better than screenshot for analysis). Large data: URL payloads in snapshot output are truncated to their media type prefix. AI snapshots mark a visually present subtree excluded from accessibility queries with [aria-hidden] on its boundary element. Descendants are not marked again.

  • Parameters: compress (optional boolean, default false), boxes (optional boolean; overrides snapshot.boxes for this call)

    • When compress is true, repeated non-interactive ARIA snapshot nodes are collapsed in the rendered response when a repeated structural pattern appears more than 100 times. The first 10 examples of each collapsed pattern are kept.

    • Use browser_evaluate() to retrieve the full uncompressed list when needed.

    • When boxes is true, each element includes [box=x,y,width,height] in viewport-relative CSS pixels.

browser_find

Search the current page accessibility snapshot without returning the full snapshot.

  • Parameters: text (case-insensitive substring) or regex (regular expression, supports /pattern/flags)

  • Returns matching snapshot lines with surrounding context, shown under their path from the root of the tree; ... marks truncated off-path context.

browser_click

Perform click on a web page element.

  • Parameters: element (description), ref (element reference), doubleClick (optional)

browser_type

Type text into editable element.

  • Parameters: element, ref, text, submit (optional), slowly (optional)

browser_hover

Hover over element on page.

  • Parameters: element, ref

browser_drag

Perform drag and drop between two elements.

  • Parameters: startElement, startRef, endElement, endRef

browser_drop

Simulate an external drag and drop of files or clipboard-like data onto an element, for testing drop zones that never see a drag start inside the page.

  • Parameters: element, ref, paths (optional array of absolute file paths), data (optional map of mime type to value, e.g. {"text/plain": "hello"})

  • At least one of paths or data is required.

  • Fails if the target's dragover handler does not accept the payload.

  • paths are read from the filesystem of the machine running the server, exactly as browser_file_upload does, and a relative path resolves against the server's working directory. Unlike browser_file_upload this needs no file chooser to be open, so any page with a dragover handler is a valid target — treat it as a tool that can hand local file contents to the page.

browser_select_option

Select an option in a dropdown.

  • Parameters: element, ref, values (array)

browser_fill_form

Fill multiple fields with one call.

  • Parameters: fields (array of objects with name, type, ref, and value)

browser_press_key

Press a key on the keyboard.

  • Parameters: key (e.g., 'ArrowLeft' or 'a')

browser_start_recording / browser_stop_recording

Record browser actions and return them as Playwright JavaScript. Start the server with --caps devtools, call browser_start_recording, perform the flow, then call browser_stop_recording.

Multi-tab recordings include the context.newPage() declarations needed by generated page aliases. Recorded assertions include the playwright/test expect setup they need to run.

Handshake-free HTTP clients must first call browser_session_open, then pass its browserSessionId to both recording tools so the recording survives across requests. Modes that cannot open separate browser sessions, such as --extension and non-isolated CDP attach, need a stateful MCP connection for recording.

browser_evaluate

Evaluate a JavaScript expression on the page, or on a specific element when a ref is provided. The function's return value is serialized back as the result.

  • Parameters: function (e.g., () => document.title or (element) => element.textContent), element (optional), ref (optional)

  • element and ref must be supplied together, or not at all; supplying one without the other is rejected.

  • A bare expression is also accepted and is wrapped automatically: document.title behaves like () => document.title, and, when element and ref are both given, element.textContent behaves like (element) => element.textContent. The parameter is always named element.

  • Whether the input is a function or an expression is decided from its source form, never from what it evaluates to, so an expression such as window.open is returned rather than called.

Screenshot & Visual Tools

browser_take_screenshot

Take a screenshot of the current page.

  • Parameters: filename (optional), type (png, jpeg, or webp), scale (css or device, default css), fullPage (optional), element/ref pair (for element screenshots)

  • scale: device captures a high-resolution screenshot using device pixels (accounts for the device pixel ratio); scale: css keeps the image sized in CSS pixels.

browser_pdf_save

Save page as PDF.

  • Parameters: filename (optional, defaults to page-{timestamp}-{token}.pdf)

This tool requires --caps pdf in the CLI.

browser_install

Install the configured browser engine (use when browser executable is missing).

  • Parameters: none

Browser Management

browser_close

Close the page.

browser_resize

Resize the browser window.

  • Parameters: width, height

browser_emulate_media

Emulate CSS media features on the current page without resetting omitted features.

  • Parameters: colorScheme (light or dark), reducedMotion (reduce or no-preference), forcedColors (active or none), contrast (more or no-preference), and media (screen or print); provide at least one.

Tab Management

browser_tabs

Manage browser tabs in one tool.

  • Parameters: action (list, new, close, select) and optional index (for close and select).

Browser Session Tools

Following the MCP 2026-07-28 stateless prescription, browser state can be named by an explicit server-minted handle instead of living implicitly in the connection. Every browser tool except the two session tools accepts an optional browserSessionId argument; when it is omitted, the tool runs in the default session and behaves exactly as before.

browser_session_open

Opens a separate browser session — its own browser context with its own tabs, cookies and storage — and returns its opaque handle (bs_...) both in the result text and as structuredContent.browserSessionId. Pass that handle as the browserSessionId argument of other browser tools to run them in this session.

How the separate context is provided depends on the mode:

  • Default persistent-profile mode: each session runs in its own fresh, disposable profile (removed when the session closes or expires); only the default session uses the stable persistent profile, whose sign-in state keeps surviving restarts. This is required — one profile directory can back only one running browser at a time.

  • --isolated, remote endpoints, and CDP/--cdp-launch with --isolated: each session gets its own fresh browser context. In --cdp-launch mode each context launches its own instance of the configured application on its own free port — which is why combining --cdp-launch-port with --isolated also rejects browser_session_open: a pinned port can serve only one launched instance, so a second session would silently attach to the first session's application. A second concurrent browser context on the pinned port (e.g. from a parallel client) is likewise rejected with an error rather than attaching to the first context's application.

  • Modes that reuse one live browser context — CDP attach or --cdp-launch without --isolated, --extension, the VS Code bridge, and servers created with a custom context getter — cannot create a separate context, so browser_session_open is rejected with an explanation instead of handing out a handle that would share the same tabs, cookies and storage as everything else. The same applies in the default mode when --user-data-dir pins all browsing to one user-supplied profile.

In --vscode serving, browser sessions are host-scoped: browser_session_open, browser_session_close, and every call carrying a browserSessionId always run against the default provider's session registry at the host, regardless of any browser_connect provider switch. A handle opened before a switch keeps working (and can be closed) while the proxy is switched to a VS Code-connected browser, and a session opened while switched is created by the default provider — the VS Code-connected browser itself reuses one live context and cannot host separate sessions. Only session-less tool calls follow the switch.

browser_session_close

Closes a session opened with browser_session_open and releases its browser resources.

  • Parameters: browserSessionId (the handle to close)

Closing is refused with a tool error while a tool call is still running in that session — a close that disposed the browser mid-call would fail the running tool; wait for it to finish and retry.

Sessions that stay idle expire automatically after 30 minutes; the timer is refreshed on every use and while a tool is running in the session (overlapping calls each count, so the session survives until the last one finishes), so a long audit_site crawl is never expired mid-run. Set PLAYWRIGHT_MCP_BROWSER_SESSION_TTL_MS to override the idle TTL in milliseconds (0 or a negative value disables expiry). Passing an unknown or expired handle produces a tool error pointing back to browser_session_open; the error deliberately does not list other open sessions' handles, since handles are bearer tokens that route tool calls into their sessions. With --save-session, logged tool calls record the browserSessionId they were routed with, and recorded user actions from an explicit session carry the same browserSessionId in their logged args, so entries from different sessions stay distinguishable (default-session entries stay untagged).

Information & Monitoring Tools

browser_console_messages

Returns all console messages from the page. Large data: URL payloads in console messages are truncated to their media type prefix.

browser_network_requests

Returns all network requests since loading the page, numbered so a single one can be inspected with browser_network_request. Large data: URL payloads in request URLs are truncated to their media type prefix. When there is at least one request, a closing line points at browser_network_request.

browser_network_request

Returns credential-redacted request/response headers and body metadata for one request from the browser_network_requests listing.

  • Parameters: index (the number shown in the listing, starting at 1)

  • The listing is cleared by browser_navigate and when the tab closes; other navigations (link clicks, form submits, history calls) leave it in place and keep appending. Re-run browser_network_requests to get current indexes.

  • Credential-bearing headers (authorization, proxy-authorization, cookie, set-cookie, x-api-key, x-auth-token) are reported as <redacted, N characters>, so their presence and size stay visible but the secret never reaches the transcript. All other headers are reported in full, one line each.

  • Request and response body contents are never returned because they can contain submitted credentials or private API data. Non-empty bodies are reported as <redacted, N bytes, mime/type>; empty bodies remain <empty>.

  • A request that failed after its response arrived reports both the status and the failure.

  • Sections that could not be read are reported in place (<headers unavailable: ...>, <body unavailable: ...>) rather than failing the whole call; reads are bounded by the default timeout, so a still-streaming response cannot hang the tool.

Utility Tools

browser_wait_for

Wait for text to appear/disappear or time to pass.

  • Parameters: time (optional), text (optional), textGone (optional)

browser_handle_dialog

Handle browser dialogs (alerts, confirms, prompts).

  • Parameters: accept (boolean), promptText (optional)

  • If the dialog was already closed outside the session (e.g. dismissed manually in a headed browser), the call succeeds, reports the dialog as already closed, and clears its leftover state instead of failing.

browser_file_upload

Upload files to the page.

  • Parameters: paths (array of absolute file paths)

browser_verify_element_visible

Verify an element by ARIA role/name.

  • Parameters: role, accessibleName

browser_verify_text_visible

Verify text visibility.

  • Parameters: text

browser_verify_list_visible

Verify list items at a snapshot reference.

  • Parameters: element, ref, items (array)

browser_verify_value

Verify an element value or checked state.

  • Parameters: type, element, ref, value

These verification tools require --caps verify:

Vision Mode Tools (Coordinate-based Interaction)

These tools require --caps vision:

browser_mouse_move_xy

Move mouse to specific coordinates.

  • Parameters: element, x, y

browser_mouse_click_xy

Click at specific coordinates.

  • Parameters: element, x, y, button (optional: left/right/middle), clickCount (optional), delay (optional, ms between mouse down and up)

browser_mouse_drag_xy

Drag from one coordinate to another.

  • Parameters: element, startX, startY, endX, endY

Note

Coordinate-based tools require element descriptions for permission checks, but the coordinates themselves are used for action targeting.

Usage Examples

Basic Accessibility Scan

1. Navigate to example.com using browser_navigate
2. Run scan_page with violationsTag: ["wcag21aa"]

Color Contrast Check

1. Use browser_navigate to go to example.com
2. Run scan_page with violationsTag: ["cat.color"]

Multi-step Workflow

1. Navigate to example.com with browser_navigate
2. Take a browser_snapshot to see available elements
3. Click the "Sign In" button using browser_click
4. Type "user@example.com" using browser_type
5. Run scan_page on the login page
6. Take a browser_take_screenshot to capture the final state

Page Analysis

1. Navigate to example.com
2. Use browser_snapshot to capture all interactive elements
3. Review console messages with browser_console_messages
4. Check network activity with browser_network_requests

Tab Management

1. Open a new tab with `browser_tabs` and `{"action":"new"}`
2. Navigate to different pages in each tab
3. Switch to a tab with `browser_tabs` and `{"action":"select", "index": 1}`
4. List all tabs with `browser_tabs` and `{"action":"list"}`

Waiting for Dynamic Content

1. Navigate to a page
2. Use browser_wait_for to wait for specific text to appear
3. Interact with the dynamically loaded content

Note: Most interaction tools require element references from browser_snapshot. Always capture a snapshot before attempting to interact with page elements.

Development

Clone and set up the project:

git clone https://github.com/JustasMonkev/mcp-accessibility-scanner.git
cd mcp-accessibility-scanner
npm install

MCP harnesses

The npm wrappers build first, then the direct harness calls every exposed MCP tool with prepared fixtures:

npm run test:mcp
npm run test:mcp:install

The Luna wrapper runs each prompt through Codex gpt-5.6-luna with xhigh reasoning. It uses a repo-scoped scanner MCP server, read-only Codex sandbox, structured PASS/FAIL evidence, and a per-prompt timeout:

npm run test:mcp:luna
npm run test:mcp:luna -- --only browser_snapshot
npm run test:mcp:luna -- --skip-optional --limit 1

Results are written under test-results/mcp-direct-harness-results/ or test-results/mcp-tool-loop-results/. Set MCP_HARNESS_RESULTS_DIR to use another output root. The Luna harness checks Codex login before starting any prompts. Its site-audit prompt uses a local HTTP fixture, not a public website. PASS requires a completed target MCP call, no failed or unfinished MCP calls, and a successful structured result. Invalid logs, failed turns, and timeouts fail the run. Non-fatal startup notices about ignored malformed local agent roles remain in the logs; they do not count as tool failures. Recovered Codex connection retries are accepted only when the turn completes successfully. Canceling the run exits with status 130.

Benchmarking tool latency

bench/mcp-bench.mjs measures what a client actually waits for: it serves a fixed synthetic site, speaks MCP to the built server over stdio, and times real tools/call round trips for navigation, interaction, snapshots and every audit tool. Build first — it runs the compiled server from lib/.

npm run build
npm run bench -- --out after.json --label after

Useful flags: --iterations <n> and --warmups <n> (defaults 5 and 1), --browser/--executable-path when the browser lives outside Playwright's own download directory, and --server <path/to/cli.js> plus --lib <path/to/lib> (supplied together) to point at a different build — that is how revisions compare:

git worktree add /tmp/baseline main && (cd /tmp/baseline && npm install && npm run build)
npm run bench -- --server /tmp/baseline/cli.js --lib /tmp/baseline/lib --out before.json --label before
npm run bench -- --out after.json --label after
npm run bench:compare -- before.json after.json

The comparison total uses only end-to-end scenarios present in both reports, so adding or removing a scenario does not distort the reported speedup.

License

MIT

Available Tools

25 tools
browser_clickB
Destructive

Perform click on a web page

ParametersJSON Schema
NameRequiredDescriptionDefault
doubleClickNoWhether to perform a double click instead of a single click
elementYesHuman-readable element description used to obtain permission to interact with the element
refYesExact target element reference from the page snapshot

TDQS

B3.3/5.0
Behavior3/5

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

Annotations indicate destructiveHint=true and readOnlyHint=false, which already signal this is a write operation that can change page state. The description adds no behavioral context beyond this, such as potential side effects (e.g., navigation, form submission) or error conditions. It doesn't contradict annotations, but offers minimal extra insight.

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, efficient sentence with no wasted words. It's front-loaded with the core action, making it easy to scan and understand quickly. Every word earns its place by conveying the essential purpose.

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?

Given the tool's complexity (interactive, destructive) and lack of output schema, the description is minimal. It covers the basic action but omits details like return values, error handling, or dependencies on other tools (e.g., browser_snapshot for ref). With annotations providing safety cues, it's adequate but leaves gaps for effective use.

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 the schema fully documents all parameters (doubleClick, element, ref). The description adds no additional meaning about parameters, such as explaining the relationship between element and ref or when to use doubleClick. This meets the baseline for high schema coverage.

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 clearly states the action ('Perform click') and resource ('on a web page'), which is specific and unambiguous. However, it doesn't distinguish this from sibling tools like browser_hover or browser_drag, which also involve element interactions, so it doesn't reach the highest score for sibling differentiation.

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 provides no guidance on when to use this tool versus alternatives. For example, it doesn't mention when to choose browser_click over browser_double_click (implied via parameter) or browser_hover, nor does it specify prerequisites like needing a browser session or element reference from browser_snapshot.

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

browser_closeB
Read-only

Close the page

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

B3.4/5.0
Behavior4/5

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

Annotations indicate readOnlyHint=true, destructiveHint=false, and openWorldHint=true, suggesting a safe, non-destructive operation that might open new contexts. The description 'Close the page' aligns with these annotations (closing is typically non-destructive in browsers, and openWorldHint could imply handling new tabs/windows). However, the description adds minimal context beyond annotations—it doesn't specify what happens after closing (e.g., if it returns to a previous page, affects browser state, or has side effects). With annotations covering safety, the bar is lower, but more behavioral detail would be helpful.

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 'Close the page' is extremely concise—three words that directly state the action. It's front-loaded with no unnecessary details, making it easy for an agent to parse. Every word earns its place, and there's no waste or redundancy.

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?

Given the tool's simplicity (0 parameters, no output schema) and annotations providing safety info, the description is somewhat complete but lacks depth. It doesn't explain what 'page' means in context of sibling tools (e.g., vs. 'browser_tab_close'), potential return values, or behavioral nuances. For a close operation, more context on effects would improve completeness, but annotations help fill gaps.

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 0 parameters with 100% coverage, so no parameters need documentation. The description doesn't mention any parameters, which is appropriate. Baseline is 4 for zero parameters, as the description doesn't need to compensate for missing schema info.

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 'Close the page' states a clear action (close) on a resource (page), but it's vague about what 'page' refers to (current tab, specific page, etc.). It doesn't distinguish from sibling tools like 'browser_tab_close' or 'browser_close' (if there were multiple close tools), though the sibling list shows 'browser_tab_close' as a distinct tool, suggesting this might close the current page/tab. The description is minimal but conveys the basic purpose.

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 provides no guidance on when to use this tool versus alternatives. For example, it doesn't specify if this closes the current page/tab, all pages, or how it differs from 'browser_tab_close' (which is a sibling tool). There's no mention of prerequisites, context, or exclusions, leaving the agent to infer usage from the tool name alone.

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

browser_console_messagesB
Read-only

Returns all console messages

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

B3.4/5.0
Behavior4/5

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

Annotations provide readOnlyHint=true, openWorldHint=true, and destructiveHint=false, indicating a safe, read-only operation with potentially open-ended data. The description adds value by specifying 'all console messages,' implying comprehensive retrieval, which complements the annotations without contradiction. However, it doesn't detail aspects like real-time vs. historical messages or format.

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, efficient sentence with no wasted words, clearly front-loaded with the core purpose. It's appropriately sized for a simple tool with no parameters.

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?

Given the tool's simplicity (0 parameters, annotations covering safety), the description is minimally adequate. However, without an output schema, it doesn't explain what 'returns' entails (e.g., format, structure, or examples of console messages), leaving gaps for an agent to understand the response fully.

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?

With 0 parameters and 100% schema description coverage, the schema fully documents the lack of inputs. The description doesn't need to add parameter details, so a baseline of 4 is appropriate as it doesn't introduce confusion or redundancy.

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 'Returns all console messages' clearly states the action (returns) and resource (console messages), but it's vague about scope and doesn't differentiate from siblings like 'browser_network_requests' or 'scan_page' that might also return browser data. It's functional but lacks specificity about what 'all' encompasses.

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 is provided on when to use this tool versus alternatives. With siblings like 'browser_network_requests' for network data or 'scan_page' for page analysis, the description doesn't help an agent decide when console messages are the appropriate target versus other browser monitoring tools.

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

browser_dragB
Destructive

Perform drag and drop between two elements

ParametersJSON Schema
NameRequiredDescriptionDefault
endElementYesHuman-readable target element description used to obtain the permission to interact with the element
endRefYesExact target element reference from the page snapshot
startElementYesHuman-readable source element description used to obtain the permission to interact with the element
startRefYesExact source element reference from the page snapshot

TDQS

B3.3/5.0
Behavior3/5

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

Annotations already declare destructiveHint=true and readOnlyHint=false, indicating this is a mutating operation. The description adds minimal behavioral context beyond this - it specifies the action involves two elements but doesn't describe what 'drag and drop' entails (e.g., visual feedback, timing, error conditions). No contradiction with annotations exists, but the description could better explain the destructive nature implied by the annotations.

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, efficient sentence that immediately conveys the core action. Every word earns its place - 'Perform' establishes it as an action tool, 'drag and drop' specifies the interaction type, and 'between two elements' clarifies the scope. No wasted words or redundant information.

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 destructive browser interaction tool with no output schema, the description is minimally adequate. It identifies the action but lacks important context about how drag-and-drop works in this implementation, what visual feedback to expect, or how to handle failures. The annotations provide safety information, but the description could better prepare the agent for this mutating operation.

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?

With 100% schema description coverage, the input schema already fully documents all four parameters. The description adds no additional parameter information beyond implying there are 'two elements' (matching start/end parameters). This meets the baseline for high schema coverage but doesn't enhance understanding of parameter usage or relationships.

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 clearly states the action ('Perform drag and drop') and specifies the relationship ('between two elements'), which distinguishes it from simpler single-element interactions like browser_click or browser_hover. However, it doesn't explicitly differentiate from other complex interactions like browser_file_upload or browser_select_option, which might also involve multi-step operations.

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 provides no guidance on when to use this tool versus alternatives. It doesn't mention prerequisites (like needing element references from browser_snapshot), nor does it explain when drag-and-drop is appropriate versus other interaction methods. The agent must infer usage from context alone.

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

browser_file_uploadA
Destructive

Upload one or multiple files

ParametersJSON Schema
NameRequiredDescriptionDefault
pathsYesThe absolute paths to the files to upload. Can be a single file or multiple files.

TDQS

A3.5/5.0
Behavior4/5

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

Annotations indicate destructiveHint=true and readOnlyHint=false, implying a write operation that modifies state. The description adds value by clarifying it handles 'one or multiple files,' which isn't covered by annotations. However, it doesn't disclose additional behavioral traits like authentication needs, rate limits, or specific effects (e.g., overwriting files).

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—a single, front-loaded sentence that directly states the tool's function without unnecessary words. Every word earns its place, making it efficient and easy to parse.

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?

Given the tool's moderate complexity (file upload with destructive potential) and rich annotations (covering safety and world hints), the description is minimally adequate. However, without an output schema or details on upload results (e.g., success/failure indicators), it leaves gaps for the agent to handle responses.

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?

The input schema has 100% description coverage, with the 'paths' parameter clearly documented as 'The absolute paths to the files to upload. Can be a single file or multiple files.' The description adds no further meaning beyond this, as it only repeats 'one or multiple files' without elaborating on path formats or constraints.

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 'Upload one or multiple files' clearly states the verb (upload) and resource (files), distinguishing it from sibling browser tools that perform actions like clicking, navigating, or taking screenshots. However, it doesn't specify the target destination or context (e.g., to a browser session or web form), which would make it more specific.

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 provides no guidance on when to use this tool versus alternatives. It doesn't mention prerequisites (e.g., needing an active browser session), context (e.g., for file input forms), or exclusions (e.g., not for downloading). This lack of usage context leaves the agent to infer from sibling tool names alone.

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

browser_handle_dialogC
Destructive

Handle a dialog

ParametersJSON Schema
NameRequiredDescriptionDefault
acceptYesWhether to accept the dialog.
promptTextNoThe text of the prompt in case of a prompt dialog.

TDQS

C2.5/5.0
Behavior3/5

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

Annotations indicate destructiveHint=true and readOnlyHint=false, suggesting a write operation with potential side effects. The description doesn't contradict this but adds minimal context beyond annotations—it implies interaction with dialogs but doesn't specify behaviors like what happens when accepting/canceling or if it affects browser state. With annotations covering safety, the description adds some value but lacks detail on consequences.

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 'Handle a dialog' is extremely concise with no wasted words. It's front-loaded and to the point, though this brevity contributes to gaps in other dimensions. Every word serves a purpose, making it structurally efficient.

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 the tool's complexity (handling dialogs with potential destructive effects), lack of output schema, and minimal description, it's incomplete. The description doesn't explain return values, error conditions, or interaction patterns, leaving significant gaps for an agent to understand how to use it effectively in context with other browser tools.

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 clear parameter descriptions in the schema (e.g., 'accept' for dialog acceptance, 'promptText' for prompt input). The description adds no additional meaning beyond the schema, such as explaining when promptText is needed or how parameters interact. Baseline 3 is appropriate since the schema fully documents parameters.

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

Purpose2/5

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

The description 'Handle a dialog' is tautological with the tool name 'browser_handle_dialog' and doesn't specify what type of dialog or what handling entails. It mentions a dialog but doesn't distinguish it from other browser tools like browser_click or browser_select_option that might interact with UI elements. The purpose is vague and doesn't provide specific action details.

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

Usage Guidelines1/5

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

There are no guidelines on when to use this tool versus alternatives. It doesn't mention prerequisites like needing an open dialog, nor does it differentiate from siblings like browser_click for button interactions or browser_select_option for dropdowns. The description offers no context for usage decisions.

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

browser_hoverA
Read-only

Hover over element on page

ParametersJSON Schema
NameRequiredDescriptionDefault
elementYesHuman-readable element description used to obtain permission to interact with the element
refYesExact target element reference from the page snapshot

TDQS

A3.5/5.0
Behavior3/5

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

Annotations already provide readOnlyHint=true, destructiveHint=false, and openWorldHint=true, indicating a safe, non-destructive operation. The description adds minimal behavioral context beyond this, stating the hover action but not detailing effects like potential UI changes or timing considerations. It doesn't contradict annotations.

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, direct sentence ('Hover over element on page') with zero wasted words. It's front-loaded and efficiently conveys the core action without unnecessary elaboration, making it easy for an agent to parse quickly.

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?

Given the tool's low complexity (simple hover action), no output schema, and rich annotations covering safety and world state, the description is minimally adequate. However, it lacks details on expected outcomes (e.g., UI feedback) or prerequisites (e.g., needing a page snapshot from browser_snapshot), leaving some contextual gaps.

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 clear descriptions for both parameters (element as human-readable description, ref as exact target reference). The description adds no additional parameter semantics beyond what the schema provides, so it meets the baseline for high schema coverage without extra value.

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 'Hover over element on page' clearly states the specific action (hover) and target (element on page). It distinguishes from siblings like browser_click (click action) and browser_type (typing action) by specifying the hover interaction, which is a distinct browser manipulation operation.

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 provides no guidance on when to use this tool versus alternatives. It doesn't mention scenarios where hovering is appropriate (e.g., triggering dropdowns, tooltips) versus when clicking or other interactions are needed, nor does it reference sibling tools like browser_click for comparison.

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

browser_installA
Destructive

Install the browser specified in the config. Call this if you get an error about the browser not being installed.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.1/5.0
Behavior4/5

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

Annotations provide readOnlyHint=false, openWorldHint=true, and destructiveHint=true, indicating it's a mutating, potentially destructive operation with open-world behavior. The description adds context by specifying it installs based on config and is error-driven, which complements the annotations without contradicting them. It doesn't detail installation steps or side effects, but adds useful operational context.

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, front-loaded with the main action and followed by usage guidance. Every word serves a purpose with no redundancy or fluff, making it highly efficient and well-structured.

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 tool has 0 parameters, annotations cover key behavioral traits, and no output schema exists, the description is reasonably complete. It explains what the tool does and when to use it, but could benefit from more details on installation behavior or error handling. However, for a simple install tool, it's adequate.

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 0 parameters, and schema description coverage is 100%, so no parameter documentation is needed. The description doesn't add param info, but that's acceptable here. Baseline for 0 params is 4, as it's complete by default.

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 clearly states the verb 'install' and the resource 'browser specified in the config', making the purpose explicit. However, it doesn't distinguish from siblings like browser-related tools (e.g., browser_navigate, browser_close), which are about browser interaction rather than installation, so it's not fully differentiated.

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 provides clear context on when to use this tool: 'if you get an error about the browser not being installed.' This gives a specific trigger condition. It doesn't explicitly state when not to use it or name alternatives, but the context is sufficient for basic guidance.

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

browser_navigateB
Destructive

Navigate to a URL

ParametersJSON Schema
NameRequiredDescriptionDefault
urlYesThe URL to navigate to

TDQS

B3.3/5.0
Behavior3/5

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

The description doesn't add behavioral information beyond what annotations provide. Annotations already indicate this is a destructive operation (destructiveHint: true) and not read-only (readOnlyHint: false), which covers the core safety profile. The description doesn't disclose additional traits like navigation behavior (e.g., page loading, timeouts, or error handling).

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 with just three words, front-loading the essential information without any wasted text. It's appropriately sized for a simple tool with one parameter and clear annotations.

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?

Given the tool's complexity (simple navigation with one parameter), rich annotations covering safety aspects, and no output schema, the description is minimally adequate. However, it lacks context about what navigation entails (e.g., loading a webpage, potential side effects) that would help an agent understand the tool's behavior more fully.

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?

With 100% schema description coverage, the input schema already documents the single 'url' parameter thoroughly. The description doesn't add any meaningful parameter semantics beyond what's in the schema, such as URL format requirements or validation rules, so it meets the baseline.

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 'Navigate to a URL' clearly states the action (navigate) and target resource (URL), making the tool's purpose immediately understandable. However, it doesn't differentiate from sibling tools like 'browser_navigate_back' or 'browser_navigate_forward' which are related navigation operations, so it doesn't reach the highest score.

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 provides no guidance on when to use this tool versus alternatives. It doesn't mention when navigation is appropriate compared to other browser actions like 'browser_click' or 'browser_type', nor does it specify any prerequisites or context for navigation operations.

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

browser_navigate_backA
Read-only

Go back to the previous page

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.2/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true, destructiveHint=false, and openWorldHint=true, covering safety and scope. The description adds no behavioral traits beyond what annotations provide, such as navigation history constraints or browser state implications. No contradiction with annotations exists.

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, efficient sentence with zero waste. It is front-loaded and appropriately sized for a simple navigation tool, making it easy to understand quickly.

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 tool with no parameters, rich annotations (readOnlyHint, destructiveHint, openWorldHint), and no output schema, the description is complete enough. It could benefit from mentioning browser context or history state, but it adequately covers the core functionality given the structured data.

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?

With 0 parameters and 100% schema description coverage, the baseline is 4. The description does not need to explain parameters, and it adds no extra parameter information, which is appropriate given the lack of inputs.

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 'Go back to the previous page' clearly states the specific action (go back) and resource (previous page). It distinguishes from siblings like browser_navigate_forward (forward navigation) and browser_navigate (general navigation), making the purpose unambiguous.

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 implies usage context (when there is a previous page to return to), but does not explicitly state when not to use it or name alternatives. It provides clear context but lacks explicit exclusions or named sibling comparisons beyond what's inferred from the tool name.

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

browser_navigate_forwardA
Read-only

Go forward to the next page

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already provide readOnlyHint=true, destructiveHint=false, and openWorldHint=true, indicating a safe, non-destructive operation. The description adds behavioral context by specifying 'to the next page', clarifying it's about browser navigation history. It doesn't contradict annotations, and adds meaningful context beyond what annotations alone provide about the specific navigation 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?

The description is a single, efficient sentence that directly states the tool's purpose without any wasted words. It's front-loaded with the core action and immediately clarifies the target ('to the next page'). Every word earns its place in this minimal yet complete description.

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 tool's simplicity (0 parameters, no output schema) and comprehensive annotations, the description is mostly complete. It could slightly improve by mentioning constraints (e.g., only works if forward history exists) or the expected outcome, but for a basic navigation tool with good annotations, it provides sufficient context for an agent to understand and invoke it 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?

The tool has 0 parameters with 100% schema description coverage. The description doesn't need to explain parameters, and appropriately doesn't mention any. It earns a baseline 4 since no parameters exist to document, and the description correctly focuses on the action rather than non-existent inputs.

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 'Go forward to the next page' clearly states the specific action (go forward) and resource (next page). It distinguishes from sibling tools like 'browser_navigate_back' by specifying the forward direction, and from 'browser_navigate' by focusing on navigation within browser history rather than to a new URL.

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 implies usage context (navigating forward in browser history), but doesn't explicitly state when to use this vs. alternatives like 'browser_navigate_back' or 'browser_navigate'. It provides clear intent but lacks explicit exclusion criteria or prerequisite conditions (e.g., only works if there's forward history available).

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

browser_network_requestsB
Read-only

Returns all network requests since loading the page

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

B3.4/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true, destructiveHint=false, and openWorldHint=true, indicating a safe, read-only operation with open-ended data. The description adds context about the temporal scope ('since loading the page'), which is useful but doesn't detail behavior like return format, pagination, or data freshness. With annotations covering core traits, this earns a baseline score for adding some value.

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, efficient sentence that front-loads the core action ('Returns all network requests') and adds necessary context ('since loading the page'). There is no wasted verbiage, making it highly concise and well-structured.

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?

Given the tool's simplicity (0 params, annotations covering safety), the description is adequate but has gaps. It lacks output details (no schema provided) and doesn't explain data scope or limitations, which could be helpful for an agent. It meets minimum viability but isn't fully comprehensive.

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 0 parameters with 100% coverage, so no parameter documentation is needed. The description doesn't add param info, but since there are no params, this is acceptable and earns a high baseline score for not being required to compensate.

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 clearly states the verb ('Returns') and resource ('all network requests since loading the page'), making the purpose specific and understandable. However, it doesn't explicitly differentiate from sibling tools like 'browser_console_messages' or 'scan_page', which might also retrieve browser data, so it doesn't reach the highest score.

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 provides no guidance on when to use this tool versus alternatives. It doesn't mention prerequisites (e.g., after page load), exclusions, or comparisons to siblings like 'browser_console_messages' for different data types, leaving usage context implied at best.

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

browser_pdf_saveB
Read-only

Save page as PDF

ParametersJSON Schema
NameRequiredDescriptionDefault
filenameNoFile name to save the pdf to. Defaults to `page-{timestamp}.pdf` if not specified.

TDQS

B3.2/5.0
Behavior3/5

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

Annotations provide readOnlyHint=true, destructiveHint=false, and openWorldHint=true, indicating a safe, non-destructive operation with flexible inputs. The description adds minimal behavioral context beyond this—it implies saving the current page but doesn't specify what 'page' means (e.g., current tab, entire page vs. viewport) or any limitations (e.g., file size, format constraints). No contradiction with annotations exists, but the description under-leverages the opportunity to clarify 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?

The description is extremely concise at three words, front-loading the core action without unnecessary elaboration. Every word ('Save', 'page', 'PDF') directly contributes to understanding the tool's function, making it efficient and easy to parse.

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 the lack of output schema and the tool's potential complexity (saving a PDF involves rendering and file I/O), the description is insufficient. It doesn't address what happens on success/failure, where the PDF is saved, or any dependencies (e.g., requires a loaded page). With annotations covering safety but not operational details, more context is needed for reliable use.

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?

With 100% schema description coverage for the single parameter 'filename', the schema fully documents its purpose and default behavior. The description adds no parameter-specific information beyond the tool's overall function, so it meets the baseline of 3 where the schema handles the heavy lifting without extra value from the description.

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 'Save page as PDF' clearly states the verb ('Save') and resource ('page as PDF'), making the purpose immediately understandable. However, it doesn't differentiate from sibling tools like 'browser_take_screenshot' or 'browser_snapshot' that might also capture page content, leaving room for confusion about when to choose this specific PDF-saving function.

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 provides no guidance on when to use this tool versus alternatives. It doesn't mention prerequisites (e.g., requires an active browser page), exclusions (e.g., can't save dynamic content), or comparisons to siblings like 'browser_take_screenshot' for image capture or 'browser_snapshot' for other formats. This lack of context could lead to inappropriate tool selection.

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

browser_press_keyB
Destructive

Press a key on the keyboard

ParametersJSON Schema
NameRequiredDescriptionDefault
keyYesName of the key to press or a character to generate, such as `ArrowLeft` or `a`

TDQS

B3.3/5.0
Behavior3/5

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

Annotations indicate destructiveHint=true and readOnlyHint=false, implying a write operation with potential side effects. The description adds no behavioral details beyond this, such as what gets affected (e.g., browser state, page focus) or any constraints like rate limits. It doesn't contradict annotations but adds minimal value beyond them.

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, clear sentence with no wasted words. It's front-loaded with the core action and target, making it highly efficient and easy to parse for an AI agent.

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?

Given the tool's moderate complexity (a destructive action with one parameter) and lack of output schema, the description is minimal but functional. It states what the tool does but lacks details on behavior, usage context, or output expectations, making it adequate but incomplete for optimal agent guidance.

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 the 'key' parameter fully documented in the schema. The description adds no additional semantic context about the parameter, such as examples beyond those in the schema or special cases. Baseline score of 3 is appropriate since the schema handles parameter documentation adequately.

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 'Press a key on the keyboard' clearly states the action (press) and target (key on keyboard), which is specific and unambiguous. However, it doesn't differentiate from sibling tools like 'browser_type' which might involve keyboard input, leaving room for improvement in sibling 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?

The description provides no guidance on when to use this tool versus alternatives. It doesn't mention when to choose 'browser_press_key' over 'browser_type' or other input-related siblings, nor does it specify any prerequisites or context for usage, leaving the agent without operational context.

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

browser_resizeB
Read-only

Resize the browser window

ParametersJSON Schema
NameRequiredDescriptionDefault
heightYesHeight of the browser window
widthYesWidth of the browser window

TDQS

B3.3/5.0
Behavior3/5

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

Annotations indicate readOnlyHint=true and destructiveHint=false, so the agent knows this is a safe, non-destructive operation. The description adds no behavioral context beyond this, such as whether resizing affects page layout, triggers events, or has limitations (e.g., minimum/maximum dimensions). It doesn't contradict annotations, but offers minimal additional insight.

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, efficient sentence with zero waste—'Resize the browser window' directly conveys the core action without unnecessary words. It's front-loaded and appropriately sized for a simple tool.

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?

Given the tool's low complexity (2 required parameters), high schema coverage, and annotations covering safety, the description is minimally adequate. However, it lacks context on output (no schema provided) or integration with sibling tools, leaving gaps for an agent to infer usage in a browser automation workflow.

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 clear descriptions for 'width' and 'height' parameters. The description adds no meaning beyond the schema, such as units (pixels), valid ranges, or default values. Baseline 3 is appropriate since the schema fully documents parameters.

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 'Resize the browser window' clearly states the action (resize) and target resource (browser window). It distinguishes from siblings like browser_click or browser_navigate by specifying the resize operation, though it doesn't explicitly contrast with similar tools like browser_snapshot which might also involve window dimensions.

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 provides no guidance on when to use this tool versus alternatives. It doesn't mention prerequisites (e.g., needing an active browser session), exclusions, or compare it to siblings like browser_tab_new or browser_snapshot that might affect window size indirectly.

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

browser_select_optionB
Destructive

Select an option in a dropdown

ParametersJSON Schema
NameRequiredDescriptionDefault
elementYesHuman-readable element description used to obtain permission to interact with the element
refYesExact target element reference from the page snapshot
valuesYesArray of values to select in the dropdown. This can be a single value or multiple values.

TDQS

B3.3/5.0
Behavior3/5

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

Annotations provide critical behavioral hints: destructiveHint=true (indicating it modifies state) and openWorldHint=true (suggesting unpredictable outcomes). The description adds minimal context beyond this, stating the action but not elaborating on risks like page reloads or validation errors. It doesn't contradict annotations, but with annotations covering safety aspects, the description's value is limited to confirming the basic action without rich behavioral details.

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, efficient sentence with zero wasted words. It's front-loaded with the core action ('Select an option in a dropdown'), making it immediately scannable. Every word earns its place, and there's no redundancy or unnecessary elaboration.

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 destructive tool with no output schema, the description is minimally adequate. Annotations cover key behavioral traits (destructive, open-world), and the schema fully documents parameters. However, the description lacks context about error conditions, what happens on success, or integration with other tools like browser_snapshot. It meets basic needs but leaves gaps for safe and effective use.

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 clear descriptions for all three parameters (element, ref, values). The description adds no parameter-specific information beyond what the schema already provides. It implies 'values' usage but doesn't clarify syntax or multi-select behavior. Given high schema coverage, the baseline score of 3 is appropriate, as the description doesn't compensate but doesn't need to.

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 'Select an option in a dropdown' clearly states the verb ('Select') and resource ('option in a dropdown'), making the purpose immediately understandable. It distinguishes this tool from siblings like browser_click or browser_type by specifying dropdown interaction, though it doesn't explicitly contrast with all similar tools like browser_handle_dialog. The description is specific but could be more precise about its unique role among browser interaction 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?

The description provides no guidance on when to use this tool versus alternatives. It doesn't mention prerequisites (e.g., needing a page snapshot from browser_snapshot first), when to prefer it over other selection methods, or any limitations. With many sibling tools for browser interaction, this lack of context leaves the agent guessing about appropriate usage scenarios.

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

browser_snapshotA
Read-only

Capture accessibility snapshot of the current page, this is better than screenshot

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A3.8/5.0
Behavior4/5

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

Annotations provide readOnlyHint=true, destructiveHint=false, and openWorldHint=true, indicating this is a safe, non-destructive operation that may return unpredictable results. The description adds value by specifying it captures 'accessibility snapshot' (implying structured accessibility data) and compares it to screenshots, giving context about what kind of data is returned. No contradiction with annotations exists.

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 with just one sentence that efficiently communicates the core purpose and key comparison. Every word earns its place: 'Capture accessibility snapshot' defines the action, 'of the current page' provides context, and 'this is better than screenshot' adds valuable differentiation. No wasted words or redundancy.

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?

Given the tool has no parameters, rich annotations (readOnly, openWorld, non-destructive), but no output schema, the description is somewhat complete but could better explain what an 'accessibility snapshot' returns. It mentions it's 'better than screenshot' which hints at richer data, but doesn't specify format or content. For a tool with behavioral complexity implied by openWorldHint, more detail about output expectations would be helpful.

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 0 parameters with 100% schema description coverage, so the schema fully documents the lack of inputs. The description appropriately doesn't discuss parameters, which is correct for a zero-parameter tool. It focuses on what the tool does rather than inputs, meeting the baseline expectation.

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 clearly states the tool's purpose: 'Capture accessibility snapshot of the current page' specifies the verb (capture) and resource (accessibility snapshot). It distinguishes from sibling 'browser_take_screenshot' by mentioning 'this is better than screenshot', though it doesn't explicitly name that sibling. The purpose is specific but could be more precise about what an 'accessibility snapshot' entails.

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 context by comparing to screenshot ('this is better than screenshot'), suggesting this tool should be used when accessibility data is needed rather than visual capture. However, it doesn't explicitly state when to use this tool versus alternatives like 'scan_page' or provide clear exclusions. The guidance is implied rather than explicit.

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

browser_tab_closeB
Destructive

Close a tab

ParametersJSON Schema
NameRequiredDescriptionDefault
indexNoThe index of the tab to close. Closes current tab if not provided.

TDQS

B3.2/5.0
Behavior3/5

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

Annotations already indicate destructiveHint=true and readOnlyHint=false, so the agent knows this is a destructive write operation. The description adds no behavioral context beyond this, such as what happens if no tabs exist, whether it's reversible, or if it requires specific permissions. However, it doesn't contradict annotations, so it meets the baseline for having annotations.

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 with just three words ('Close a tab'), which is front-loaded and wastes no space. Every word directly contributes to understanding the tool's purpose, making it efficient and easy to parse.

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 the destructive nature (destructiveHint=true) and lack of output schema, the description is insufficient. It doesn't explain what happens after closing a tab (e.g., browser behavior, return values, or error conditions), leaving gaps that could confuse an agent in practical use. The annotations help but don't fully compensate for missing contextual details.

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?

The input schema has 100% description coverage, with the parameter 'index' fully documented in the schema itself. The description adds no additional meaning about parameters, such as explaining tab indexing conventions or edge cases. This aligns with the baseline score when schema coverage is high.

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 'Close a tab' clearly states the action (close) and resource (tab), making the purpose immediately understandable. It distinguishes from siblings like browser_tab_list (list tabs) and browser_tab_new (create tab), though it doesn't explicitly contrast with them. The description is specific but lacks explicit sibling differentiation, which keeps it from a perfect score.

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 provides no guidance on when to use this tool versus alternatives. It doesn't mention prerequisites (e.g., needing an open tab), exclusions, or compare with related tools like browser_close (which might close the entire browser). Without such context, an agent might struggle to apply it correctly in complex scenarios.

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

browser_tab_listB
Read-only

List browser tabs

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

B3.4/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true, destructiveHint=false, and openWorldHint=true, indicating a safe, read-only operation that may return variable data. The description adds no behavioral context beyond what annotations provide, such as whether it returns tab titles, URLs, or order, or if there are rate limits. It doesn't contradict annotations, so a baseline score is appropriate.

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 'List browser tabs' is extremely concise—just three words—and front-loaded with the core action. Every word earns its place by directly conveying the tool's function without any fluff or redundancy, making it highly efficient for quick understanding.

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?

Given the tool's low complexity (0 parameters, no output schema) and rich annotations (readOnlyHint, openWorldHint), the description is minimally complete. It states what the tool does but lacks details on output format or usage context. For a simple list operation, this is adequate but leaves gaps that could be filled with a bit more information.

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 0 parameters with 100% coverage, so no parameter documentation is needed. The description doesn't add parameter details, which is acceptable here. A score of 4 reflects that the description is adequate given the lack of parameters, though it could briefly note the absence of inputs for clarity.

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 'List browser tabs' clearly states the action (list) and resource (browser tabs), making the purpose immediately understandable. It distinguishes from siblings like browser_tab_close or browser_tab_new by focusing on listing rather than modifying tabs. However, it doesn't specify if it lists all tabs or just active ones, keeping it from a perfect score.

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 provides no guidance on when to use this tool versus alternatives. It doesn't mention prerequisites (e.g., needing an open browser), exclusions, or comparisons to siblings like browser_tab_select for navigation. This lack of context leaves the agent to infer usage based on the name alone.

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

browser_tab_newA
Read-only

Open a new tab

ParametersJSON Schema
NameRequiredDescriptionDefault
urlNoThe URL to navigate to in the new tab. If not provided, the new tab will be blank.

TDQS

A3.6/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true, openWorldHint=true, and destructiveHint=false, covering safety and scope. The description adds minimal context ('new tab' implies creation, not modification of existing tabs), but doesn't detail behavioral aspects like whether it focuses the tab, handles errors for invalid URLs, or interacts with browser state beyond what annotations provide.

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 'Open a new tab' is a single, front-loaded sentence with zero waste. It efficiently conveys the core action without unnecessary words, making it highly concise and well-structured.

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 tool's low complexity (one optional parameter), rich annotations (covering safety and scope), and no output schema, the description is mostly complete. However, it lacks context on usage scenarios or integration with sibling tools, leaving minor gaps for an AI agent to infer optimal use.

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 the parameter 'url' fully documented in the schema. The description doesn't add any semantic details beyond what's in the schema (e.g., URL format, default behavior). With high schema coverage, the baseline score of 3 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 'Open a new tab' is a specific verb+resource action that clearly distinguishes it from siblings like browser_tab_close (close), browser_tab_list (list), or browser_tab_select (select). It precisely states what the tool does without ambiguity.

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 provides no guidance on when to use this tool versus alternatives. It doesn't mention prerequisites (e.g., needing an open browser), exclusions (e.g., not for opening windows), or comparisons to siblings like browser_navigate (which might reuse existing tabs).

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

browser_tab_selectB
Read-only

Select a tab by index

ParametersJSON Schema
NameRequiredDescriptionDefault
indexYesThe index of the tab to select

TDQS

B3.3/5.0
Behavior3/5

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

Annotations provide readOnlyHint=true, destructiveHint=false, and openWorldHint=true, indicating a safe, non-destructive operation with potential for unknown outcomes. The description adds minimal behavioral context beyond this—it specifies 'by index' but doesn't explain what happens if the index is invalid, if selection changes focus, or any side effects. It doesn't contradict annotations, but offers little extra insight into tool 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?

The description is a single, efficient sentence: 'Select a tab by index'. It's front-loaded with the core action and method, with zero wasted words. Every part earns its place, making it highly concise and well-structured for quick understanding.

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?

Given the tool's low complexity (1 parameter, no output schema) and rich annotations (covering safety and world hints), the description is minimally adequate. It states what the tool does but lacks completeness in usage guidelines, error handling, or integration with siblings like browser_tab_list. For a simple selection tool, it meets basic needs but leaves gaps in operational context.

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?

The input schema has 1 parameter with 100% description coverage ('The index of the tab to select'), so the schema fully documents the parameter. The description adds no additional meaning beyond what's in the schema—it repeats 'by index' without clarifying format (e.g., zero-based vs. one-based) or constraints. Baseline score of 3 is appropriate as the schema carries the burden.

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 'Select a tab by index' clearly states the action (select) and resource (tab), with the method specified (by index). It distinguishes from siblings like browser_tab_list (lists tabs) and browser_tab_close (closes tabs), though it doesn't explicitly contrast them. The purpose is specific but could be more distinctively positioned among similar tab operations.

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 provides no guidance on when to use this tool versus alternatives. It doesn't mention prerequisites (e.g., needing an open browser or existing tabs), when not to use it (e.g., if no tabs exist), or direct alternatives like browser_tab_list for identifying indices. Usage is implied by the action but lacks explicit context for decision-making.

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

browser_take_screenshotA
Read-only

Take a screenshot of the current page. You can't perform actions based on the screenshot, use browser_snapshot for actions.

ParametersJSON Schema
NameRequiredDescriptionDefault
elementNoHuman-readable element description used to obtain permission to screenshot the element. If not provided, the screenshot will be taken of viewport. If element is provided, ref must be provided too.
filenameNoFile name to save the screenshot to. Defaults to `page-{timestamp}.{png|jpeg}` if not specified.
rawNoWhether to return without compression (in PNG format). Default is false, which returns a JPEG image.
refNoExact target element reference from the page snapshot. If not provided, the screenshot will be taken of viewport. If ref is provided, element must be provided too.

TDQS

A4.2/5.0
Behavior3/5

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

Annotations already declare readOnlyHint=true, destructiveHint=false, and openWorldHint=true, covering the safety profile. The description adds useful context about the tool's limitations (no action capability) and distinguishes it from browser_snapshot, but doesn't provide additional behavioral details like rate limits, authentication needs, or what happens to the screenshot file after creation.

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 with just two sentences, both of which earn their place by providing essential purpose clarification and usage guidance. No wasted words or redundant information.

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 tool's moderate complexity (screenshot capture with element targeting options), the description provides good purpose and usage context. With annotations covering safety aspects and no output schema, the main gap is lack of information about return values or what happens to the screenshot file, but the description adequately covers the core functionality.

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?

With 100% schema description coverage, the input schema already fully documents all 4 parameters. The description doesn't add any parameter-specific information beyond what's in the schema, so it meets the baseline expectation when schema coverage is complete.

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 specific action ('Take a screenshot') and resource ('current page'), and explicitly distinguishes it from the sibling tool 'browser_snapshot' by stating 'use browser_snapshot for actions'. This provides clear differentiation from alternatives.

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 provides explicit guidance on when NOT to use this tool ('You can't perform actions based on the screenshot') and names a specific alternative ('use browser_snapshot for actions'). This gives clear context for tool selection versus sibling tools.

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

browser_typeB
Destructive

Type text into editable element

ParametersJSON Schema
NameRequiredDescriptionDefault
elementYesHuman-readable element description used to obtain permission to interact with the element
refYesExact target element reference from the page snapshot
slowlyNoWhether to type one character at a time. Useful for triggering key handlers in the page. By default entire text is filled in at once.
submitNoWhether to submit entered text (press Enter after)
textYesText to type into the element

TDQS

B3.3/5.0
Behavior3/5

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

Annotations indicate destructiveHint=true and readOnlyHint=false, which the description aligns with by implying mutation ('type text'). It adds minimal context about typing behavior but doesn't detail side effects like page changes or error handling, relying heavily on annotations for safety profile.

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, clear sentence with zero waste, front-loading the core action. It's appropriately sized for the tool's complexity, making it easy to parse without unnecessary elaboration.

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?

Given the tool's moderate complexity, annotations cover safety, and schema fully documents parameters, but no output schema exists. The description lacks details on return values or error cases, leaving gaps in completeness despite structured data support.

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 parameters are fully documented in the schema. The description adds no extra meaning beyond the schema, such as explaining interactions between parameters like 'slowly' and 'submit'. Baseline score of 3 applies as the schema handles documentation.

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 clearly states the action ('type text') and target ('into editable element'), which is specific and actionable. However, it doesn't differentiate from sibling tools like browser_press_key or browser_file_upload that also involve text input, missing explicit 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 is provided on when to use this tool versus alternatives such as browser_press_key for keyboard input or browser_file_upload for file inputs. The description lacks context about prerequisites or typical scenarios, offering no usage instructions.

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

browser_wait_forA
Read-only

Wait for text to appear or disappear or a specified time to pass

ParametersJSON Schema
NameRequiredDescriptionDefault
textNoThe text to wait for
textGoneNoThe text to wait for to disappear
timeNoThe time to wait in seconds

TDQS

A3.5/5.0
Behavior3/5

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

Annotations already provide readOnlyHint=true, destructiveHint=false, and openWorldHint=true, indicating a safe, non-destructive operation. The description adds behavioral context about what triggers the wait (text appearance/disappearance or time), which is valuable beyond annotations. However, it doesn't specify timeout behavior, error conditions, or what happens if multiple conditions are specified.

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, efficient sentence that front-loads the core functionality with zero wasted words. It directly communicates the tool's purpose without unnecessary elaboration, making it easy to parse quickly.

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 tool with 3 parameters, 100% schema coverage, and annotations covering safety, the description is adequate but minimal. It lacks details on output (no output schema), error handling, or integration with sibling tools (e.g., use after browser_navigate). Given the complexity is moderate, it meets minimum viability but could be more complete.

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 clear parameter descriptions in the schema. The description adds minimal value by summarizing the parameters ('text to appear or disappear or a specified time'), but doesn't provide additional semantics like parameter interactions, default behaviors, or examples. Baseline 3 is appropriate given the comprehensive 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 clearly states the tool's purpose with specific verbs ('wait for text to appear or disappear or a specified time to pass'), making it immediately understandable. It distinguishes itself from siblings like browser_click or browser_type by focusing on waiting rather than performing actions. However, it doesn't explicitly mention it's for browser automation context, though sibling tools provide that context.

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 scenarios (waiting for text changes or timeouts) but doesn't provide explicit guidance on when to use this versus alternatives. No sibling tools offer similar waiting functionality, so differentiation isn't needed, but it lacks context about prerequisites (e.g., needing an active browser session) or typical use cases.

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

scan_pageB
Destructive

Scan the current page for accessibility violations using Axe

ParametersJSON Schema
NameRequiredDescriptionDefault
violationsTagYesArray of tags to filter violations by. If not specified, all violations are returned.

TDQS

B3.3/5.0
Behavior3/5

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

Annotations provide readOnlyHint=false, openWorldHint=true, and destructiveHint=true, indicating this is a non-read-only, open-ended, and potentially destructive operation. The description adds that it scans 'the current page' and uses 'Axe', giving implementation context. However, it doesn't explain what 'destructive' means here (e.g., page reload, state changes) or detail output behavior (e.g., format, timing), leaving gaps despite annotations.

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, efficient sentence that front-loads the core purpose without unnecessary words. Every part ('Scan the current page for accessibility violations using Axe') contributes essential information, making it appropriately sized and well-structured for quick understanding.

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?

Given the tool's moderate complexity (accessibility scanning with filtering), annotations cover safety and scope, and schema fully documents the single parameter. However, without an output schema, the description doesn't explain what the scan returns (e.g., violation details, counts), leaving a gap in understanding results. It's adequate but incomplete for effective use.

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 the parameter 'violationsTag' fully documented in the schema as an array of tags to filter violations. The description adds no parameter-specific information beyond what the schema provides, so it meets the baseline for high schema coverage without compensating value.

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 clearly states the action ('Scan') and resource ('current page') with the specific purpose of finding 'accessibility violations using Axe'. It distinguishes itself from sibling browser tools by focusing on accessibility scanning rather than navigation, interaction, or monitoring. However, it doesn't explicitly differentiate from potential non-existent accessibility siblings.

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 provides no guidance on when to use this tool versus alternatives. It doesn't mention prerequisites (e.g., needing an open browser page), when scanning is appropriate (e.g., after page load), or what happens if used incorrectly. With many sibling browser tools, this lack of context leaves the agent guessing about proper sequencing.

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. Dates show when Glama detected each change.

  1. 25 tool updatesv1.0.0
    • First observedbrowser_click
    • First observedbrowser_close
    • First observedbrowser_console_messages
    • First observedbrowser_drag
    • First observedbrowser_file_upload
    • First observedbrowser_handle_dialog
    • First observedbrowser_hover
    • First observedbrowser_install
    • First observedbrowser_navigate
    • First observedbrowser_navigate_back
    • First observedbrowser_navigate_forward
    • First observedbrowser_network_requests
    • First observedbrowser_pdf_save
    • First observedbrowser_press_key
    • First observedbrowser_resize
    • First observedbrowser_select_option
    • First observedbrowser_snapshot
    • First observedbrowser_tab_close
    • First observedbrowser_tab_list
    • First observedbrowser_tab_new
    • First observedbrowser_tab_select
    • First observedbrowser_take_screenshot
    • First observedbrowser_type
    • First observedbrowser_wait_for
    • First observedscan_page

TDQS

B3.4/5.0
Disambiguation4/5

Most tools have distinct purposes, but there is some overlap between browser_snapshot and browser_take_screenshot, as both capture page visuals, though their descriptions clarify different use cases. Other tools like browser_navigate, browser_navigate_back, and browser_navigate_forward are clearly differentiated, and actions like click, hover, and type are well-separated.

Naming Consistency5/5

All tool names follow a consistent snake_case pattern with a 'browser_' prefix for most tools, except scan_page which still fits the style. The naming is highly predictable, using verb_noun combinations like browser_click, browser_navigate, and browser_tab_list, making it easy to understand and navigate.

Tool Count3/5

With 25 tools, the count is borderline high for an accessibility scanner, as it includes many general browser automation functions beyond core accessibility tasks. While comprehensive, it may feel heavy and could be streamlined by focusing more on accessibility-specific operations rather than broad browser control.

Completeness4/5

The toolset covers a wide range of browser interactions and includes a dedicated accessibility scanning tool (scan_page), but there are minor gaps such as lacking tools for specific accessibility audits like color contrast checks or ARIA attribute validation. However, the core functionality for navigating, interacting, and scanning pages is well-covered.

Maintenance

ActivityActive
ResponsivenessWithin a week

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • F
    license
    A
    quality
    D
    maintenance
    Enables comprehensive WCAG 2.0/2.1 accessibility testing of web applications using Playwright and axe-core. Supports natural language element finding, auto-discovery of interactive components, and generates detailed compliance reports with screenshots.
    2
    -
  • A
    license
    A
    quality
    C
    maintenance
    Enables AI coding agents to perform real-browser accessibility scanning of localhost pages using Playwright and axe-core, returning WCAG 2.1 violations with structured fix plans.
    3
    93
    1
    MIT

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/JustasMonkev/mcp-accessibility-scanner'

If you have feedback or need assistance with the MCP directory API, please join our Discord server