@real-a11y-dev/mcp
Beta — preview page
Published on npm as a beta: the API and tool surface may still change before 1.0, and audit fidelity is bounded by known engine issues. Pin a version rather than tracking the latest tag if you build on it.
The Real A11y MCP server gives an AI assistant a real browser and the accessibility tree behind any page, so it can audit a URL and report the defects a screen reader would announce — not guess from pasted HTML (which hides computed roles and visibility) or a screenshot (which has no semantics). Point any Model Context Protocol client at it and ask it to audit a page in plain language.
Accessibility is a property of the rendered page — the roles, names, and visibility a browser actually computes, not what's in the HTML source. So the server drives a real browser (via Playwright) rather than parsing markup. You need:
- Node.js 20+ — the server runs under Node and is fetched with
npx. - A Chrome binary — install one with
npx real-a11y install(downloads Chrome for Testing;npx playwright install chromiumalso works). - An MCP client — Claude Code, Claude Desktop, Cursor, VS Code, Windsurf, or any other MCP-capable tool.
Connect it to your client
The server speaks MCP over stdio — point your client at npx -y @real-a11y-dev/mcp. No install step is needed; npx fetches it on first run.
claude mcp add real-a11y -- npx -y @real-a11y-dev/mcpcode --add-mcp '{"name":"real-a11y","command":"npx","args":["-y","@real-a11y-dev/mcp"]}'{
"mcpServers": {
"real-a11y": {
"command": "npx",
"args": ["-y", "@real-a11y-dev/mcp"]
}
}
}For clients configured by file, add the mcpServers block above to:
- Claude Desktop —
claude_desktop_config.json(Settings → Developer → Edit Config). - Cursor —
~/.cursor/mcp.json, or a project-local.cursor/mcp.json. - Windsurf and others — that client's MCP config, using the same block.
Then install a browser once:
npx real-a11y installTo pin a version instead of tracking the latest, add it to your project (npm install -D @real-a11y-dev/mcp playwright) and point command / args at the local install.
The server picks up an installed browser automatically. To point it at a specific binary instead (a system Chrome, say), set REAL_A11Y_CHROME_PATH; REAL_A11Y_BROWSERS_DIR overrides where real-a11y install caches its download if you don't want the platform default (~/.cache/real-a11y). A CDP connection (REAL_A11Y_MCP_CDP) ignores both — it reuses whatever browser is already running.
Your first audit
Once it's connected, ask in plain language — the assistant picks the tools:
You: "Audit example.com for accessibility problems."
Assistant: calls
open_page("https://example.com")→audit_page()→ gets structured findings → explains them and proposes fixes.
Because it drives a real browser, JS-heavy SPAs render fully, and any URL the browser can reach works — public sites, a local dev server, or staging.
Every tool + parameters → /packages/mcp/tools
This is a guide. For the full tool reference — all twenty tools, their parameters, and when to reach for each — see the tools reference.
Auditing a page behind a login
To audit a page only a logged-in user can see, save a browser session once, then point the server at it — the assistant never touches credentials.
Save a session with the CLI's login helper (a one-time human step):
shnpx -y @real-a11y-dev/cli login https://app.example.com --save auth.jsonA real browser opens; sign in by hand (passwords, SSO, MFA, and passkeys all work), then press Enter. Playwright's storage state — cookies and origin storage — is written to
auth.json. Keep that file out of version control; it holds live session tokens.Point the server at it with two environment variables in your MCP config:
json{ "mcpServers": { "real-a11y": { "command": "npx", "args": ["-y", "@real-a11y-dev/mcp"], "env": { "REAL_A11Y_MCP_STORAGE_STATE": "/absolute/path/to/auth.json", "REAL_A11Y_MCP_ALLOWED_ORIGINS": "https://app.example.com" } } } }Audit as usual. Every page now opens already authenticated, and
open_pagetells the assistant the session is active so it won't try to log in.REAL_A11Y_MCP_ALLOWED_ORIGINSpins auditing to that origin, so a redirect can't route your session to another site.
The session path is server configuration, never a tool argument, so tokens stay out of the assistant's context. See Authenticated pages for the full workflow and security rules.
Configuration
All server behavior is set through REAL_A11Y_MCP_* environment variables, in the "env" block of the config above — attaching to a running Chrome over CDP, headful mode, file:// access, a saved login session, origin pinning, and the named-session limits (REAL_A11Y_MCP_MAX_SESSIONS, REAL_A11Y_MCP_SESSION_IDLE_TIMEOUT_MS). Each one, with its values and security notes, is documented in Environment in the tools reference.
Every page tool also takes an optional session parameter — independent named live pages with their own checkpoints, serialized within a session and parallel across sessions. Omit it and the server behaves as a single-page tool; the tools reference has the full semantics.
Scripting audits without an MCP client
Same engine, no agent: the route is the CLI. @real-a11y-dev/cli runs these audits from a shell script or a CI job and prints them in machine formats, so nothing in the pipeline has to speak MCP.
npx -y @real-a11y-dev/cli audit https://example.com --format json -o report.json- The audit itself —
auditexits1on error-severity findings, so it gates a build with no configuration;--format jsonwith-owrites the same findingsaudit_pagereports. - Multi-step flows —
--session <name>keeps one browser alive across invocations, so successive commands read the same live page instead of reloading it — the shell's version of thesessionparameter above. - Acting on the page —
click,type, andfocustarget a control by role + accessible name and print the tree diff the action caused;interact --step '<step>'chains several of them in one run. - Gating a PR —
snapshotwrites the diffable artifact, anddiff base.json pr.jsonclassifies findings as new / changed / fixed inpretty,json, ormd(--format md -o comment.mdis the PR-comment shape).
Every command and flag is in Commands & flags.
What the CLI cannot give you is an in-process Node API, and no other package does either now. The Playwright-backed session lives in @real-a11y-dev/browser, which was published through 0.1.0-beta.13 and is workspace-internal from mcp@0.1.0-beta.4 on: it is bundled into this server, the CLI, and the testing adapter, and there is nothing to install by that name. Two narrower doors stay open, neither a replacement for it:
- You already have a Playwright
Page—attach(page)from@real-a11y-dev/testing/playwrightruns the same audit helpers against it, and stays public. - You are embedding this server — it re-exports
BrowserSessionalong withA11ySession,BrowserSessionOptions,PageSnapshot, andSnapshotOptions, becausebuildServertakes anA11ySessionand a customSessionManagerhas to name that contract. That is an embedding surface, not a session package: it arrives with the whole MCP SDK dependency graph, which is exactly what installingbrowseron its own used to avoid.
How it compares to Playwright MCP
This complements a browser-automation MCP such as Playwright MCP — it doesn't try to replace it. Both can act on a page now, but they act for different reasons:
- Playwright MCP drives a page for automation breadth — arbitrary selectors, hover, drag, file uploads, multiple tabs — using the accessibility snapshot as a means to act.
- Real A11y acts through the accessibility tree and judges what changed. Its act tools target role + accessible name only — a control the tools can't reach is itself an accessibility smell — and every action pairs with
diff_tree's answer to "what did that change for a screen reader?". Its audit reports what assistive technology would announce as broken.
For an accessibility flow — open the dialog, judge the dialog — Real A11y now stands alone. For automation verbs it doesn't ship (hover, drag, uploads, multi-tab), pair the two: drive with Playwright MCP, judge with Real A11y.
Two different "Playwrights"
This package is built on Playwright the library — the browser driver you install as a peer dependency. It complements Playwright MCP, the automation server above. Same underlying engine, different jobs.
Limitations
- Scope. It runs five rules today — unlabeled interactive elements, images missing alt text, heading order, dialog labeling, and landmark structure — plus the full semantic tree. It is not a complete WCAG or axe-core suite; it is semantic-tree-based and tuned to "what a screen reader announces." For contrast, focus visibility, and other rendered/interactive checks, pair it with axe-core and manual testing.
- Fidelity follows the engine. The tree is a reimplementation of accessible-name / role computation, not the browser's native accessibility tree. It is tuned to match what assistive tech announces, but can diverge on edge cases.
- Requires a real browser. The assistant's environment must be able to launch Chromium or connect to one over CDP.
See also
- Tools reference — every tool, its parameters, and when to use it.
@real-a11y-dev/testing— Assertions — the samecollectFindingsengine, for unit and end-to-end tests.