MCP Server
Vesper Audit includes a Model Context Protocol (MCP) server. Point a compatible AI client at it and that assistant can run accessibility scans directly, as part of a conversation, instead of you exporting a report and attaching it to one. MCP is an open standard, so this works with any client that supports it.
The workflow this exists for is the remediation loop. You change a template, ask the assistant to rescan the page, and see whether the finding cleared - without leaving what you were doing. That is why scan_url is the primary tool: a single-page rescan is the operation you repeat, while a full crawl is something you do once at the start.
Requirements
- Vesper Audit installed in your Applications folder.
- Google Chrome installed. Vesper drives your real Chrome; it does not bundle its own.
- Any MCP-compatible client. Model Context Protocol is an open standard - the server does not know or care what is on the other end. Claude Desktop, Claude Code and Cowork are the clients Vesper Audit has been tested against; Cursor, Zed, VS Code and others speak MCP too and configure the same way.
You do not need Node.js installed. The configuration below runs the copy of Node that ships inside Vesper Audit.
Setting it up
The exact configuration is also shown in the app, under Settings > MCP server, with a copy button. Copying it from there is less error-prone than retyping it, because the paths must match exactly.
Claude Desktop
Open Settings > Developer > Edit Config, which opens claude_desktop_config.json, and add the vesper-audit entry inside mcpServers:
{
"mcpServers": {
"vesper-audit": {
"command": "/Applications/Vesper Audit.app/Contents/MacOS/Vesper Audit",
"args": ["/Applications/Vesper Audit.app/Contents/Resources/app.asar/mcp-server.js"],
"env": { "ELECTRON_RUN_AS_NODE": "1" }
}
}
}
If you already have other servers configured, add this one alongside them rather than replacing the block. Restart the client afterwards - the tools do not appear until it restarts.
Claude Code
claude mcp add vesper-audit --env ELECTRON_RUN_AS_NODE=1 -- "/Applications/Vesper Audit.app/Contents/MacOS/Vesper Audit" "/Applications/Vesper Audit.app/Contents/Resources/app.asar/mcp-server.js"
Other clients
Any client that supports MCP over stdio can run this server. The three pieces are always the same - a command, its arguments, and one environment variable:
- Command:
/Applications/Vesper Audit.app/Contents/MacOS/Vesper Audit - Arguments:
/Applications/Vesper Audit.app/Contents/Resources/app.asar/mcp-server.js - Environment:
ELECTRON_RUN_AS_NODE=1
That environment variable is not optional. Without it the command launches Vesper Audit as a normal desktop app instead of starting the server.
Checking it worked
Ask the assistant to scan any page. If it reports that no such tool exists, see Troubleshooting below.
The tools
scan_url
Audits a single page and returns the findings. This is the one to reach for when checking a fix.
| Argument | Type | Notes |
|---|---|---|
url | string, required | Full URL of the page. A bare hostname is accepted and corrected. |
includeBestPractices | boolean | Also report axe best-practice rules that are not WCAG failures. Default false. |
detail | summary or full | summary truncates fix text and HTML snippets. Default summary. |
maxInstances | number | Example instances returned per rule. Default 3. |
viewportWidth | number | 320-3840. Default 1280. Use around 390 to check mobile layout. |
Takes roughly 5-15 seconds. Available on every license tier, matching the free single-page scan in the app.
scan_site
Crawls a whole site and returns aggregated findings, with template issues that repeat across pages collapsed into a single finding carrying a page count rather than reported hundreds of times.
| Argument | Type | Notes |
|---|---|---|
url | string, required | Site URL to start from. |
maxPages | number | Stops after this many pages. Default 25, maximum 250. |
includeBestPractices | boolean | Default false. |
checkLinks | boolean | Also check external links and PDFs for broken URLs. Slower. Default false. |
detail | summary or full | Default summary. |
maxInstances | number | Default 3. |
Budget roughly one second per page. Requires a Supporter license, trial, or founder unlock - the same gate as a full crawl in the app.
The default of 25 pages is deliberately low. Start small, look at what comes back, then raise it.
check_contact_links
Checks every tel: and mailto: link on a page for a broken href. This catches links whose visible text looks perfectly correct but whose href will not dial or open a mail client - URL-encoded parentheses, literal spaces, a malformed address. The defect is invisible to sighted review, so it is worth checking explicitly after any edit to contact details.
Returns a clean bill of health when nothing is broken, which is a useful answer in its own right.
What comes back
Findings are returned as compact structured data rather than a full report, so that a scan does not consume the context it was meant to save. Each finding carries the rule, its severity, how many instances were found and on how many pages, and a few example instances.
Each instance names where it is:
landmark- the ARIA landmark the element sits in (banner,contentinfo,navigation, and so on).container- the nearest identifiable container element, with its id.containerClass- the same container as a class-only signature. This is the field to match on when writing a rule that has to work across several sites, because the same component often carries a different id on each one while the class list stays identical.rendered- present andfalsewhen the element was not visible at scan time. Findings on hidden elements are still reported, but they do not count against the clean-page total.fix- the remediation text.
The response also reports scannedWith, naming the Vesper Audit and axe-core versions that produced it. Rule behavior changes between versions, so when comparing a scan against an earlier one, check that field first.
Pages that look like soft 404s or maintenance pages are surfaced separately under scanWarnings. A page like that can scan clean simply because there is nothing on it to fail, so it should not be counted as passing.
Privacy
Scans run entirely on your machine using your own Chrome install. The only network traffic is to the site being scanned. No scan data is sent to Vesper or anywhere else.
Your AI client is a separate matter and worth understanding: findings are returned to whatever assistant you pointed at the server, and that assistant handles them under its own provider's terms. Vesper has no part in that and cannot see it. If a site is sensitive, that is the question to ask - not of Vesper, but of the client you are using.
The server reads the same settings file as the app, so path, query, and regex exclusions configured in Vesper Audit apply to MCP scans too. This is deliberate: without it, a page excluded in the app would reappear in an MCP scan and the two surfaces would quietly disagree about what is in scope.
Troubleshooting
The tools do not appear in the client. Restart the client - it only reads its MCP configuration at startup. If they are still missing, check the paths in the configuration against where Vesper Audit is actually installed. The app must be in /Applications, or the paths must be edited to match.
Scans report an older version of Vesper Audit than the one you installed. Restart your MCP client after upgrading the app. The client starts the server once and keeps that process alive, so a server started before the upgrade goes on running the previous version of Vesper Audit - and its results will look entirely normal apart from the scannedWith field. Check scannedWith whenever a result does not match what you expect from a new build.
"Google Chrome was not found." Vesper drives your real Chrome rather than bundling one. Install Chrome and try again.
A full-site crawl is refused. scan_site requires a Supporter license, trial, or founder unlock. Start a trial in the app, under Settings > License & plan. scan_url keeps working regardless.
A crawl returns fewer pages than expected. Check maxPages, which defaults to 25, and then check your exclusion settings in the app - those apply here too.
Scans are slow. A crawl loads every page in a real browser and runs a full axe pass, so roughly a second per page is normal. Use scan_url for single pages and keep maxPages low while exploring.