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

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:

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.

ArgumentTypeNotes
urlstring, requiredFull URL of the page. A bare hostname is accepted and corrected.
includeBestPracticesbooleanAlso report axe best-practice rules that are not WCAG failures. Default false.
detailsummary or fullsummary truncates fix text and HTML snippets. Default summary.
maxInstancesnumberExample instances returned per rule. Default 3.
viewportWidthnumber320-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

This is the one that runs a real audit. It crawls the whole site and writes the same JSON, CSV, Markdown and optional PDF bundle the app produces, into the output folder configured in Settings and using the same folder naming. It returns a job id straight away rather than making the assistant wait, and scan_status reports progress and hands back the path when it finishes.

ArgumentTypeNotes
urlstring, requiredSite URL to start from.
maxPagesnumberDefaults to the page budget configured in the app, so a normal call audits the whole site. Set it low, 10 to 25, only for a quick look.
includeBestPracticesbooleanDefault false.
checkLinksbooleanCheck external links and PDFs for broken URLs. Default true, matching a normal audit.
formatsobject{ pdf, markdown, csv, zip }. CSV and Markdown default on, PDF off, zip follows your app setting. The JSON is always written. PDF is rendered with your own Chrome when the scan is started from an assistant rather than the app, and is identical either way.

Requires a Supporter license, trial, or founder unlock - the same gate as a full crawl in the app.

The findings are not in the response, and that is deliberate. It returns summary counts and the path to what it wrote. Every violation instance, image warning, PDF link, broken link, overlay and link-decoration row is in the JSON on disk at full fidelity - a large site runs to hundreds of rows, which no tool response can carry, and reading the file costs the assistant almost no context.

One thing to know: closing your AI client mid-crawl loses the job. The export is written when the crawl finishes, so nothing is saved if the client goes away first. Just run it again.

scan_status

Takes the job id from scan_site. Reports progress while the crawl runs, and on completion returns the path to the results JSON and the audit folder, the summary counts, and the size of each dataset - so an empty array can be told apart from one that was never collected.

It also reports whether the crawl was truncated, and how many URLs were left unvisited. If a crawl stops at its page cap it is not a finished audit of the site, however complete the numbers look, and this is where that is said plainly.

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:

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 the page budget configured in the app, and then check your exclusion settings - those apply here too. If the crawl stopped at its cap the response says so and reports how many URLs it never reached.

Scans are slow. A crawl loads every page in a real browser and runs a full axe pass, so expect two to three seconds per page with link checking on. A 100-page site takes about five minutes. Times were measured on a Mac Mini over a home connection; a slower network moves the range. Use scan_url for single pages and keep maxPages low while exploring.