Skip to main content
Version: v6

MCP Server

The AudioEye MCP server (@audioeye/testing-sdk-mcp) is a Model Context Protocol server that lets an AI coding agent scan a live page for accessibility issues and propose source-level fixes. It drives a real browser, scans the page with the AudioEye Testing SDK, attaches a JSX source location to each issue where it can, and exposes the results to your agent as MCP tools.

Use it with any MCP-capable coding agent: Claude Code, Cursor, VS Code, Codex, Gemini CLI, Windsurf, Zed, or Claude Desktop.

Setup takes three steps: install, sign in, scan. Unlike the rest of the SDK, the MCP server is published to the public npm registry and licensed through a browser sign-in, so it needs no private-registry configuration and no copied credentials on a developer machine. The other SDK packages keep their own setup; see Getting Started.

Requirements

  • Node.js 22.12 or later. The SDK supports every Node.js LTS line that has not reached end of life, currently 22 and 24. Claude Desktop users installing the .mcpb bundle don't need Node.js; the bundle runs on Claude Desktop's own runtime.
  • An AudioEye account with Testing SDK access. If the Testing SDK Client Token card doesn't appear under Account settings in the AudioEye Customer Portal, contact your AudioEye representative.
  • macOS or Linux for full file-write containment. The server also runs on Windows, where symlink containment is best-effort.

Step 1: Install and register

Install the package globally, then let setup register the server with every MCP host it finds on your machine:

npm install -g @audioeye/testing-sdk-mcp
audioeye-mcp setup

setup with no flags detects Claude Code, Codex, Gemini CLI, Cursor, VS Code, Windsurf, and Zed, and registers the server with each one at user (machine-wide) scope under the key audioeye. Hosts prefix tool and prompt names with that key (mcp__audioeye__scan, and so on). For Claude Code, setup also adds mcp__audioeye__* to permissions.allow so the tools don't prompt on every call.

setup is safe to re-run, and audioeye-mcp setup --dry-run prints what it would detect and write without touching anything. Restart your coding agent afterwards so it picks up the new server.

Why a global install?

setup registers the absolute path of the installed audioeye-mcp binary. Registering the npx -y form instead makes the host re-resolve the package from its own working directory on every launch, and a workspace whose package.json carries a conflicting npm overrides block then kills the server at startup (the host just shows "Connection closed"). Install globally and let setup register the binary.

Register with a specific host

Pass one or more host flags to configure only those hosts. Each tab also shows the equivalent manual registration.

audioeye-mcp setup --claude --global # user scope: `claude mcp add --scope user` + ~/.claude/settings.json
audioeye-mcp setup --claude # project scope: `claude mcp add` + ./.claude/settings.json

Both forms add the mcp__audioeye__* permissions rule. To register by hand instead:

claude mcp add audioeye -- audioeye-mcp

Step 2: Sign in

audioeye-mcp login
  1. The terminal prints a short pairing code and opens your browser to the AudioEye portal's device-approval page with the code pre-filled. If the browser doesn't open, use the printed link.
  2. Sign in to the portal if prompted, confirm the code matches your terminal, and click Approve. The page shows which user and account you're granting access as.
  3. The terminal reports Signed in as you@example.com (Your Account). Credentials are stored with owner-only permissions at ~/.config/audioeye/credentials.json (%APPDATA%\audioeye\credentials.json on Windows). No secret is displayed or pasted by hand.

Two companion commands:

  • audioeye-mcp whoami shows the active identity and whether it comes from the stored sign-in or from environment variables.
  • audioeye-mcp logout deletes the stored credentials. Environment variables are left alone.

The sign-in is stored once per machine and shared by every AudioEye SDK package installed there.

Claude Desktop

The .mcpb install has no terminal. Sign in from the chat instead; see Signing in on Claude Desktop.

Signing in on Claude Desktop

Ask Claude to sign you in to AudioEye. It calls the audioeye_login tool:

  1. The first call returns a pairing code and a link to the portal's device-approval page.
  2. Open the link, confirm the code matches, and click Approve.
  3. Ask Claude to check again. The tool reports signed_in once the approval lands. It polls in the background and writes the same credential store as audioeye-mcp login, so every other MCP host on the machine is signed in too.

If you've already run audioeye-mcp login on this machine, Claude Desktop is signed in already. The license token is never returned to the host or shown in the chat.

CI and other non-interactive environments

Where a browser sign-in isn't possible, provide the license credentials as the AUDIOEYE_TESTING_SDK_CLIENT_ID and AUDIOEYE_TESTING_SDK_CLIENT_TOKEN environment variables instead. See CI/CD integration in Getting Started for where to find them and how to store them.

A stored sign-in takes precedence. The SDK falls back to the environment variables when there is no sign-in or when the stored credentials fail validation. If a host configuration needs the variables inline, reference them by name so the committed file never carries the token (Claude Code's .mcp.json variable expansion shown):

.mcp.json
{
"mcpServers": {
"audioeye": {
"command": "audioeye-mcp",
"env": {
"AUDIOEYE_TESTING_SDK_CLIENT_ID": "${AUDIOEYE_TESTING_SDK_CLIENT_ID}",
"AUDIOEYE_TESTING_SDK_CLIENT_TOKEN": "${AUDIOEYE_TESTING_SDK_CLIENT_TOKEN}"
}
}
}
}

Step 3: Scan

Start your app's development server, then ask your agent to run the bundled prompt against it:

/mcp__audioeye__scan-and-fix http://localhost:3000

The agent opens an AudioEye-controlled Chrome window (log in to your app there if needed), scans the page, and presents a deterministic summary of failures with JSX source locations. With your approval it proposes source-level fixes and re-scans to verify them.

Prefer smaller steps? /mcp__audioeye__scan only scans and summarizes; /mcp__audioeye__fix proposes fixes against the scan persisted by a previous run.

Available tools

The server exposes these tools to your agent. Every tool that touches the AudioEye engine requires a valid license (sign-in or environment variables) and fails closed without one; rule metadata lookups are the exception.

  • audioeye_open_browser launches (or focuses) a Chrome window with a persistent profile at ~/.cache/audioeye-mcp/profile/, so login state survives between scans.
  • audioeye_scan scans the current page, attaches a JSX source location to each failing element where possible, and returns grouped results with rule metadata plus a server-rendered summaryMarkdown report. The agent presents the report verbatim, so the same scan produces the same summary on every host.
  • audioeye_get_rule_metadata looks up metadata for rule codes from an earlier scan.
  • audioeye_get_source_context reads the lines around a source location from a previous scan. Reads are confined to the workspace.
  • audioeye_get_a11y_facts computes assistive-technology facts (accessible name, role, resolved ARIA attributes, nearest landmark) for an element on the current page.
  • audioeye_verify_fix re-scans after a fix and reports whether the targeted failure is resolved.
  • audioeye_close_browser shuts the browser down while preserving the profile.
  • audioeye_login signs in through browser device pairing for hosts with no terminal (see Signing in on Claude Desktop). It succeeds immediately when credentials are already present.

The Chrome window is owned by the server process your agent spawned. When the agent exits, Chrome exits with it; the persistent profile keeps your login state for the next session.

Bundled prompts

Three prompts ship with the server, registered through the standard MCP prompts API. Every host that surfaces MCP prompts exposes them automatically under its own naming. In Claude Code they appear as:

  • /mcp__audioeye__scan (optional url argument) scans a live URL and summarizes the failures. No code edits.
  • /mcp__audioeye__fix proposes source-level fixes against an existing scan result. Does not run a scan.
  • /mcp__audioeye__scan-and-fix (optional url argument) runs the full flow: scan, summarize, propose fixes (only with your approval), and verify.

Prompt updates arrive with the package. There are no per-repository command files to maintain.

Configuration

The server reads these optional environment variables from the host that launches it:

Optional environment variables the MCP server reads and what each one controls.
VariablePurpose
AUDIOEYE_MCP_WORKSPACERepository root used for .audioeye-mcp.json discovery, persisted scans, and source reads. Defaults to the server's working directory. Set it when the host's working directory is not the repository root.
AUDIOEYE_MCP_CONFIG_PATHAbsolute path to an ignore config file, bypassing the workspace-root search.
AUDIOEYE_MCP_PROFILE_DIRLocation of the persistent Chrome profile. Defaults to ~/.cache/audioeye-mcp/profile.
AUDIOEYE_MCP_HEADLESSSet to 1 or true to run Chrome headless. Defaults to headed so you can log in to your app interactively.

When source-level fixes are limited

The server resolves a source location for failing elements in React projects running a development build. In some situations it reports a failure but cannot point to the line that authored it:

  • Non-React projects (Vue, Svelte, Angular, plain HTML): failures are reported without a source location.
  • Production or minified builds: source mapping works only when the build ships source maps.
  • CMS-rendered content: alt text, headings, and link names authored in a CMS live in the CMS, not in your source, so the fix is a content change.
  • React Server Components without 'use client': server-rendered markup is opaque to the in-browser scan. Mark the component's file with 'use client' to restore precise mapping.
  • Third-party iframes and closed shadow roots: the DOM inside is rendered by code you don't own or can't traverse.

In these cases the scan still surfaces the issue; it just cannot always propose a code diff.

Ignoring specific issues

Real pages carry noise you can't fix at source: third-party widgets (Chargebee, Stripe, Intercom), dev-only tooling (TanStack Router Devtools, React Query Devtools), and runtime-injected vendor iframes. Suppress these with a checked-in .audioeye-mcp.json at your repository root. The server reads it on every scan and filters matching failures out of the results before the agent summarizes or proposes fixes.

.audioeye-mcp.json
{
"ignore": [
{
"cssSelector": "footer.TanStackRouterDevtools",
"comment": "Dev-only widget; not shipped to prod."
},
{
"ruleCode": "Iframe_Name_Missing",
"cssSelector": "iframe#cb-master-frame",
"comment": "Vendor SDK iframe — vendor-owned."
},
{
"fileNameContains": "node_modules/",
"comment": "Don't try to patch dependencies."
}
]
}

Each entry under ignore is a matcher with one or more of these optional fields:

Fields available on an ignore matcher entry and when each one matches.
FieldMatches when…
ruleCodethe failing rule code equals this value exactly
cssSelectorthe failing element — or any of its ancestors — matches this CSS selector
fileNamePrefixthe resolved source file path starts with this string
fileNameContainsthe resolved source file path contains this string
comment(not a matcher) free-text note explaining why the entry exists

cssSelector is a real CSS selector evaluated against the live DOM during the scan, so attribute selectors ([data-devtools]) and structural selectors (footer:has(> .TanStackRouterDevtoolsPanel)) work. Because ancestors match too, a single selector suppresses everything inside a container.

An entry must specify at least one matcher field. Fields within an entry are AND'd (all must match); separate entries are OR'd (an issue matching any entry is suppressed). Every scan response reports configPath, totalIgnored, and per-rule hit counts, so reviewers can audit exactly what was filtered.

The agent manages this file for you: when it notices noise you repeatedly dismiss, it suggests an ignore entry, but it treats .audioeye-mcp.json like source code and won't write to it without your approval. Because the file is checked in, the same suppressions apply for every developer and in CI.

By default the server looks for .audioeye-mcp.json (or audioeye-mcp.config.json) by walking up from the workspace root. Set AUDIOEYE_MCP_CONFIG_PATH to point at a config file in a non-standard location.

Troubleshooting

Tools fail with a license message

Not signed in to AudioEye. Call the audioeye_login tool to sign in… means the server found neither a stored sign-in nor both environment variables. Run audioeye-mcp login (or ask the agent to call audioeye_login), then retry.

The AudioEye testing SDK token is invalid or inactive. means credentials were found but rejected. Run audioeye-mcp whoami to see which identity is active, then:

  • if it reports a stored sign-in, run audioeye-mcp login again to refresh it
  • if it reports environment variables, confirm both are exported in the environment that launched your agent and that the Client Token has not been revoked by a refresh in the portal

See How licensing works for the license check and the offline grace window.

The server is not listed in my agent

Restart your agent after registering the server, then confirm the registration landed: claude mcp list in Claude Code, or audioeye-mcp setup --dry-run to see what setup detects. Re-running audioeye-mcp setup repairs a missing or drifted entry.

The server starts and immediately disconnects

If the host shows "Connection closed" as soon as it launches the server, the registration is probably using the npx -y @audioeye/testing-sdk-mcp form inside a workspace with a conflicting npm overrides block. Install the package globally and re-run audioeye-mcp setup so the host launches the installed binary instead.

Other issues

For browser-runtime problems shared with the rest of the SDK, see the main Troubleshooting guide.