New:Microsoft Teams Notifications Are Now Available in Socket.Learn more →
Get Started

@audioeye/testing-sdk-mcp

Package Overview
Dependencies
Maintainers
2
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@audioeye/testing-sdk-mcp

Scans live pages with the AudioEye rules engine and maps accessibility issues to JSX source.

latest
Source
npmnpm
Version
6.2.0
Version published
Weekly downloads
105
176.32%
Maintainers
2
Weekly downloads
 
Created
Source

@audioeye/testing-sdk-mcp

An MCP server that lets your AI coding assistant find and fix accessibility issues in your web app. It opens a browser, scans a page with the AudioEye engine, points each issue at the line of React code that produced it, and hands the results to the assistant so it can propose fixes.

It works in any tool that supports MCP (Model Context Protocol), such as Claude Code, Cursor, VS Code, Codex, and Claude Desktop. This README calls that tool your "host".

Before you start

  • Node.js 22 or newer. Node 22 and 24 are supported. Check with node --version.
  • An AudioEye account with Testing SDK access. The scanner is licensed. You sign in once from your host; every scan checks that sign-in. Without it, scanning tools stop with an SdkLicenseError. Looking up rule descriptions works without signing in.

Install

The package is on the public npm registry. Nothing to configure, no tokens. Every button and mcp add one-liner below registers npx --prefix / -y @audioeye/testing-sdk-mcp@latest; --prefix / keeps npx from reading the open folder's package.json (see Troubleshooting), npx caches the package after the first start, and @latest picks up new releases on restart. setup registers that same line with each host it finds. Codex alone gets it through your login shell, <your shell> -lic 'exec npx --prefix / -y @audioeye/testing-sdk-mcp@latest' (Windows: cmd /c npx --prefix / -y @audioeye/testing-sdk-mcp@latest), because the Codex VS Code plugin starts servers with a bare system PATH and cannot find npx on its own. Terminal commands (setup, login, whoami, logout) keep the plain npx -y form. The server is registered under the name audioeye, so its tools show up as mcp__audioeye__….

One command for every host

npx -y @audioeye/testing-sdk-mcp@latest setup

This finds every supported host installed on your machine (Claude Code, Cursor, VS Code, Windsurf, Zed, Codex, Gemini CLI) and registers the server in each one for all your projects. Add --dry-run to see what it would change without changing anything. Then restart your host. Options are listed under What gets registered.

Or set up one host

Each of these registers the server for all your projects. docs/install-links.md has the full list, including Codex, Gemini CLI, and VS Code Insiders.

Cursor

Install in Cursor

VS Code (GitHub Copilot and other MCP features built into VS Code)

Install in VS Code

Or from a terminal:

code --add-mcp '{"name":"audioeye","command":"npx","args":["--prefix","/","-y","@audioeye/testing-sdk-mcp@latest"]}'

If you use the Claude Code extension inside VS Code, use the Claude Code command below instead. The extension reads Claude Code's settings, not VS Code's.

Claude Code

Install it as a plugin, with no terminal. The plugin pulls the npm package for you:

/plugin marketplace add https://downloads.audioeye.com/mcp/marketplace.json
/plugin install audioeye-mcp@audioeye

Plugin installs name the server plugin_audioeye-mcp_audioeye, so its tools appear as mcp__plugin_audioeye-mcp_audioeye__audioeye_scan and its prompts as /mcp__plugin_audioeye-mcp_audioeye__scan. A direct registration uses the plain audioeye name. Use one or the other, not both, or two copies of the server run.

Or register it directly from a terminal:

claude mcp add audioeye --scope user -- npx --prefix / -y @audioeye/testing-sdk-mcp@latest

Claude Desktop

Open Settings, then Developer, then Edit Config. Add this to claude_desktop_config.json and restart Claude Desktop:

{
  "mcpServers": {
    "audioeye": {
      "command": "npx",
      "args": ["--prefix", "/", "-y", "@audioeye/testing-sdk-mcp@latest"]
    }
  }
}

Or install the one-click bundle: download audioeye-mcp.mcpb and open it with Claude Desktop. The same file is attached to each GitHub release (org access needed).

Sign in

Ask your assistant to sign in to AudioEye. It calls the audioeye_login tool, which replies with a short code and a link. Open the link, check the code, and click Approve. That is all. Nothing to copy or paste, and no terminal needed. Any scanning tool you run before signing in, or after a saved sign-in stops working, tells you to do this.

Your sign-in is saved on your machine at ~/.config/audioeye/credentials.json (on Windows, %APPDATA%\audioeye\credentials.json), readable only by you.

The same sign-in works from a terminal. It opens the browser for you:

npx -y @audioeye/testing-sdk-mcp@latest login
  • npx -y @audioeye/testing-sdk-mcp@latest whoami shows who is signed in and where the sign-in came from. It reports the saved sign-in when one exists, otherwise environment variables.
  • npx -y @audioeye/testing-sdk-mcp@latest logout removes the saved sign-in. Environment variables are left alone.

If you also use the AudioEye command-line tool aetest, aetest login is the same sign-in. Do it once and both work.

For automated runs with no one at the keyboard, see Using it in CI.

Use it

The server ships three prompts. Every host that supports MCP prompts lists them automatically. In Claude Code they are slash commands:

  • /mcp__audioeye__scan (optional: a URL) scans the page and shows a summary of the issues, with the source file and line for each one where known. It does not change any code. It saves the scan under .agent/a11y-scans/ so the fix step can read it later.
  • /mcp__audioeye__fix proposes code changes for a scan you already ran, either from the current conversation or from the saved file. It does not run a new scan.
  • /mcp__audioeye__scan-and-fix (optional: a URL) does everything: opens the browser, waits for you to log in to your app if needed, scans, shows the summary, proposes fixes after you approve, and checks that the fixes worked.

A typical first run: start your app's dev server, then ask your assistant to run /mcp__audioeye__scan-and-fix http://localhost:3000.

The prompt text is built from the files in prompts/_partials/. You do not copy anything into your repo. New prompt versions arrive with the next host restart.

Staying up to date

Every registration except the .mcpb bundle (which runs its bundled entry) runs npx --prefix / -y @audioeye/testing-sdk-mcp@latest. npx caches the package after the first start (about 60 MB, a few seconds on a normal connection) and resolves @latest on each start, so restarting the host runs the newest release when npm can reach the registry; a warm start takes about three seconds. With no network, npm may fail to start the server at all; npx --offline -y @audioeye/testing-sdk-mcp@latest is not something a host runs, so get back online and restart the host. The server also checks npm for a newer version once a day and adds a short "newer version available, restart the host" note to tool results until you restart. The Claude Code plugin updates through the marketplace instead.

Using it in CI

In CI and other automated runs, there is no one to approve a sign-in. Provide credentials as environment variables instead:

  • AUDIOEYE_TESTING_SDK_CLIENT_ID: your Testing SDK client id.
  • AUDIOEYE_TESTING_SDK_CLIENT_TOKEN: the matching token.

Both come from the AudioEye Platform under My Account, then Testing SDK, then CI credentials. Put them in your CI secret store. A saved browser sign-in wins when both exist; the variables are the fallback.

When a host config needs them, reference the variable names so the committed file never holds the secret. Example for Claude Code's .mcp.json, which supports variable expansion:

{
  "mcpServers": {
    "audioeye": {
      "command": "npx",
      "args": ["--prefix", "/", "-y", "@audioeye/testing-sdk-mcp@latest"],
      "env": {
        "AUDIOEYE_TESTING_SDK_CLIENT_ID": "${AUDIOEYE_TESTING_SDK_CLIENT_ID}",
        "AUDIOEYE_TESTING_SDK_CLIENT_TOKEN": "${AUDIOEYE_TESTING_SDK_CLIENT_TOKEN}"
      }
    }
  }
}

Never commit the token itself, and never pass it as a command-line flag. Flags are visible to other processes on the machine and end up in shell history.

Troubleshooting

  • The host shows "Connection closed" right after install. Every registration (the buttons, the one-liners, and setup) starts the server with npx, which runs from the folder your host opened and reads that folder's package.json. If its overrides conflict with one of its own dependencies, npm refuses to run anything there (EOVERRIDE). Every registration above passes --prefix / so npx skips that file. A registration written by hand without it needs --prefix / added, or the package.json fixed (the same conflict breaks npm install there). An .npmrc in that folder (or your home directory) that points the @audioeye scope at another registry sends npx there too.
  • The tools ask for sign-in every time. Check whoami (see Sign in). The saved sign-in is tried first; environment variables are only used as a fallback when nothing is saved or the saved sign-in fails validation.
  • The browser closes when the host closes. That is expected. The browser belongs to the server process the host started, and it exits with it so no stray browser stays open. Your login state in that browser is kept at ~/.cache/audioeye-mcp/profile/ for next time.
  • The host keeps running an old version. The host runs the npx of whichever Node your login PATH selects (nvm, Volta, and similar tools each bring their own). Check with npx -y @audioeye/testing-sdk-mcp@latest --version in a fresh terminal, then restart the host. Node 22+ applies to that Node, so it must be the default the shell's profile selects.
  • Codex logs JSON parse errors at startup. Codex starts the server through your login shell, so a shell rc file that prints to stdout (a greeting, nvm use output) corrupts the MCP stream. Guard those lines with case $- in *i*) … ;; esac (bash), [[ -o interactive ]] && [[ -t 1 ]] (zsh), or status is-interactive; and isatty stdout (fish), or move them out of the rc file.

What gets registered

setup registers the server in every supported host it finds:

npx -y @audioeye/testing-sdk-mcp@latest setup            # every host found, for all projects
npx -y @audioeye/testing-sdk-mcp@latest setup --dry-run  # show what would change; change nothing
  • Pick hosts with --claude, --cursor, --vscode, --windsurf, --zed, --codex, --gemini. With no host flag it uses every host it finds (--all-detected) and registers for all projects (--global). Adding a host flag installs for the current project only; add --global to keep it available in every project, for example:

    npx -y @audioeye/testing-sdk-mcp@latest setup --claude --global
    
  • --global registers Claude Code at user scope (and updates ~/.claude/settings.json), VS Code in your user profile mcp.json rather than the project's .vscode/mcp.json, and Gemini at user scope. The other hosts only have user-level config. VS Code is included in --all-detected only with --global, so setup never writes into a project by accident.

  • What it writes: for Claude Code, Codex, and Gemini it runs that host's own mcp add command, or edits the same file when the command is not installed (~/.claude.json, ~/.codex/config.toml, .gemini/settings.json). For Cursor, VS Code, Windsurf, and Zed it edits the host's JSON config (~/.cursor/mcp.json, mcp.json, ~/.codeium/windsurf/mcp_config.json, ~/.config/zed/settings.json). It only touches the audioeye entry and never writes secrets. For Codex it also sets startup_timeout_sec = 60 on that entry (Codex's default is 10 s, which a first npx start can exceed while it downloads the package); a larger value you already set is kept, and codex mcp add has no flag for it, so setup writes the key into ~/.codex/config.toml after the add.

  • Claude Code also gets mcp__audioeye__* added to its allowed tools, so the tools stop asking for permission on every call. Tools that only read (audioeye_scan, audioeye_get_a11y_facts, audioeye_get_rule_metadata, audioeye_get_source_context) are also marked read-only per the MCP spec, so hosts that auto-approve read-only tools skip the prompt anyway.

  • The command: npx --prefix / -y @audioeye/testing-sdk-mcp@latest for Claude Code, Cursor, VS Code, Windsurf, Zed and Gemini, which resolve npx from your login PATH themselves; --prefix / keeps npx from reading the open workspace's package.json, whose conflicting overrides would abort the start with EOVERRIDE. Codex alone gets <your shell> -lic 'exec npx --prefix / -y @audioeye/testing-sdk-mcp@latest' on macOS and Linux ($SHELL, or /bin/sh when unset) and cmd /c npx --prefix / -y @audioeye/testing-sdk-mcp@latest on Windows, because the Codex VS Code plugin starts servers with a bare system PATH where npx is missing; a login + interactive shell reads the same profile and rc files as your terminal. Before writing anything, setup runs npx --prefix / -y @audioeye/testing-sdk-mcp@latest --version through that login shell and warns when it fails, since Codex would fail the same way and the other hosts need the same npx. If that check fails, setup prints a warning, still writes every host entry, and exits with an error code.

  • bash users: a login shell reads ~/.bash_profile (or ~/.profile), not ~/.bashrc. nvm's installer writes its lines to ~/.bashrc, so that file must be sourced from the login file for the host to find nvm's node. Ubuntu's and macOS's default login files already do this; if yours does not, add [ -f ~/.bashrc ] && . ~/.bashrc to ~/.bash_profile.

Safe to run again: existing entries are updated, never duplicated. If one host fails, the others are still set up and setup exits with an error code.

Tools

These are the tools the assistant calls. You normally use them through the prompts above.

  • audioeye_open_browser({ url? }): opens (or focuses) a visible Chrome window with its own saved profile at ~/.cache/audioeye-mcp/profile/, so logins survive between scans. Safe to call again.
  • audioeye_scan({ url?, runOptions?, waitForReadyMs?, viewport?, inspector? }): scans the session's tab (the tab audioeye_open_browser or the first url scan opened; a new one replaces it if it closes or stops responding), walks the React component tree to attach a source location (fileName:lineNumber:columnNumber) to each failing element, and returns the scan report as Markdown, nothing else. Every scan is saved in full to .agent/a11y-scans/<session>/scan-<n>.json, one folder per server session named by the time of its first scan, and the report as scan-<n>.md beside it; the result always links both files. A report longer than 8000 characters is not returned inline: the result is a short header linking both files. Rule details (title, description, sourceFixGuidance, severity, …) are in the scan JSON under metadata[ruleCode]. The rule code in the Rule column links to the rule's page on the AudioEye Platform (https://portal.audioeye.com/rules/<ruleCode>?rulesVersion=<a11y-rules version>; the query carries the @audioeye/a11y-rules version bundled in this build so the page can show the matching metadata), which shows the rule's description, impact, WCAG mapping and fix guidance without a login. Each failure table has an Impact column after Rule (High, Medium, Low, or — when the rule catalogue rates no impact on the component), and rows are ordered by that impact first. waitForReadyMs is the maximum wait before the scan (default 5000 ms), not a fixed delay: the scan starts once the body shows text or media, no network request has been in flight for 500 ms, and React's dev source capture has stopped changing. The scan JSON records waitedMs and waitCapMs; when the wait hits the cap, the report says so and suggests scanning again. viewport: { width, height } (CSS px) is set on the tab before navigating and stays on that tab for later scans. The scan JSON records the viewport in effect at scan time; pass it to audioeye_verify_fix to check a fix at the same size. They also record scannedAt (ISO-8601 UTC) and sessionId, the server session that ran the scan, so a scan from another session can be told apart. When a fileName (a Vite /@fs/… or /src/… dev-server path, a webpack URL, or a plain path) points inside the workspace, the entry also carries filePath (absolute) and workspacePath (relative). The report links those as [workspacePath:line](workspacePath#Lline), so IDE hosts open the file at that line. When the path matches files in several projects (such as /src/App.tsx in two apps), no file is picked: the entry carries candidates (relative paths) instead, and the Source cell lists them after ambiguous:. fileName itself is never changed.
  • audioeye_inspect({ componentKey, instance? }): selects a component from the latest scan in the inspector panel: scrolls it into view, outlines it on the page, and reveals it in DevTools. Returns { componentKey, instance, resolved, cssSelector, elementId }.
  • audioeye_get_rule_metadata({ ruleCodes }): looks up rule details for codes from an earlier scan that is no longer in the conversation. New scans include this already.
  • audioeye_get_source_context({ source, contextLines? }): reads the lines around a source location from a scan. Accepts the dev-server fileName as-is and resolves it to the workspace file, or returns an error listing the candidates when it matches several. Refuses paths outside the workspace (AUDIOEYE_MCP_WORKSPACE or the current directory), naming the checkout the file lives in. The result carries resolvedRoot (the checkout holding the file). When a scan's absolute sources resolve outside the workspace, the scan JSON lists them per checkout in sourceRoots and the report says the running dev server is not this checkout.
  • audioeye_get_a11y_facts({ cssSelector }): reports what assistive technology sees for an element in the session's tab: accessible name (accessibleName, always a string, "" when the tree computed no name), role (roleSource says whether it came from the accessibility tree or the role attribute), resolved aria-* attributes, nearest landmark, nearest focusable ancestor (its accessibleName and role come from the browser's accessibility tree), and inheritedAtHidden. nearestLandmark and nearestFocusableAncestor are present only when such an ancestor exists; the element itself never counts as its own focusable ancestor.
  • audioeye_verify_fix({ ruleCode, source, url?, waitForReadyMs?, viewport? }): scans again after a fix and reports whether that (ruleCode, fileName, lineNumber) failure is gone, allowing for the line to have moved by up to 15 lines.
  • audioeye_close_browser(): closes the browser. The profile is kept.
  • audioeye_login(): signs in without a terminal. The first call returns a pairing code and an approval link; approve it in the browser and call again to check. On success the sign-in is saved to the shared store, so the terminal tool and every other host are signed in too. When a saved sign-in exists, the call re-checks it and starts a new pairing if it no longer works. The license token never leaves the server.

Inspector panel

When the server's own Chrome window scans a page, it adds a small panel to that tab. A launcher pill appears in a corner when the page loads. Opening it lists the components from the latest scan; clicking one shows its rules, source location, and instances. Each component row carries one High, Medium, or Low pill for the highest impact among its failing rules, and the rules list in the details view shows a pill before each rated rule code. Selecting an instance scrolls the live element into view, outlines it, draws Chrome's inspect-element highlight, and, when DevTools is open, selects the node in the Elements panel (so $0 in the console is that element). A Scan button in the panel runs a new scan without a prompt. When DevTools is open and has the file loaded, the source path becomes a link that opens the file in the Sources panel at that line.

When the panel received the scan, the scan result says so and the scan JSON records inspectorMounted: true. When the panel is off for a reason the caller did not choose, the report says why and names the step that brings it back. The assistant selects components with audioeye_inspect.

Settings:

  • "inspector": false in .audioeye-mcp.json turns the panel off for the project. It is on by default.
  • audioeye_scan({ inspector: true | false }) overrides that for one tab. The first scan in a tab decides; close the browser to change it.
  • Headless runs (AUDIOEYE_MCP_HEADLESS=1) never get the panel.
  • A Chrome another AudioEye MCP server launched (shared profile) follows the same rules; the panel goes only in the tab this server opened.
  • The panel lives in one [data-ae-inspector] element with a shadow root and is excluded from every scan result.
  • The panel adds two page globals: AudioEyeMCP, installed through a single CDP Runtime.addBinding, and AudioEyeInspector, the panel's own API.

Configuration

A .audioeye-mcp.json file in your project hides issues you have decided not to fix. The server looks for it starting at the workspace root (AUDIOEYE_MCP_WORKSPACE if set, otherwise the current directory) and walking up.

{
  "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."
    }
  ]
}

All fields in one entry must match; any entry matching is enough. The scan report lists which config file was used and how many issues each entry hid, so reviewers can see what was filtered. It also warns when an entry's cssSelector is the page root (html, body, :root) or when one entry hides more than a quarter of the page's failures (5 or more).

cssSelector is checked against the live page with element.closest on the element or any shadow host that encloses the element, so one selector covers the element itself, anything inside a matching container, and everything in a matching host's open shadow roots.

Ignoring dev-tool and third-party widget failures

Dev-only panels and vendor widgets (router or query devtools, error overlays, chat widgets, cookie banners) can add many failures you will never fix. Each unmapped failure carries a topLevelSelector naming its top-level container, and on the first scan of a page the agent proposes one ignore entry per container it judges to be tooling or a third-party widget. It asks before editing the config. To add one yourself, ignore the container's root selector. For example, for TanStack Router and TanStack Query devtools:

{
  "ignore": [
    { "cssSelector": ".TanStackRouterDevtools, .TanStackRouterDevtoolsPanel", "comment": "Dev-only widget." },
    { "cssSelector": ".tsqd-transitions-container, .tsqd-main-panel", "comment": "Dev-only widget." }
  ]
}

"inspector": false next to ignore turns off the inspector panel for the project.

Environment variables

License (for CI; on your own machine, use Sign in instead)

  • AUDIOEYE_TESTING_SDK_CLIENT_ID and AUDIOEYE_TESTING_SDK_CLIENT_TOKEN: see Using it in CI. A saved sign-in wins when present; the variables are used when there is no sign-in or the saved one fails validation. With neither, every browser, scan, verify, and a11y-facts call stops with SdkLicenseError.

Optional

  • AUDIOEYE_MCP_PROFILE_DIR: where the browser profile lives. Default ~/.cache/audioeye-mcp/profile.
  • AUDIOEYE_MCP_HEADLESS: 1 or true runs Chrome without a window. Default is a visible window so you can log in to your app.
  • AUDIOEYE_MCP_WORKSPACE: the repo root used for saved scans, audioeye_get_source_context, and the .audioeye-mcp.json lookup. Default is the current directory. Set it when the host starts the server somewhere other than the repo root.
  • AUDIOEYE_MCP_CONFIG_PATH: an absolute path to a config file, skipping the lookup.

Limitations

File reads and writes (saved scans, audioeye_get_source_context) refuse to follow symlinks out of the workspace, using O_NOFOLLOW plus a realpath check on the parent folder. On Windows, O_NOFOLLOW does nothing in some Node versions, so only the parent-folder check applies there. Run the server on macOS or Linux for full protection.

Which React versions map issues to source

For each failing element the scan tries these sources in order:

  • fiber._debugSource: React 16 and 17 (with @babel/plugin-transform-react-jsx-source) and React 18.0 to 18.2.
  • fiber._debugStack: React 19. The dev runtime captures a stack at the JSX call site; the scanner reads the first user frame.
  • A jsxDEV/jsxsDEV wrapper on webpack chunk globals that records sources in a WeakMap. Covers React canaries that drop both fields above, including the build Next.js 14 pins.
  • A React.cloneElement hook that carries the recorded source from the original element to the clone, so wrapper patterns (MUI or Joy <IconButton component={NextLink}>, Storyblok link wrappers) keep their source.
  • Babel classic transform: props.__source when present.
  • V8 [[FunctionLocation]] plus source maps: when the scan knows the component function but not its source, the server asks Chrome for the compiled position, fetches the bundle's source map, and decodes it. These matches are tagged confidence: 'passthrough' with passthroughReason: 'component-function-location'. This is what makes production builds work when they ship source maps.
  • Last resort: Function.prototype.toString() on the component. The dev JSX transform (SWC and Babel) leaves a literal {fileName, lineNumber, columnNumber} in the compiled body, which the scanner reads. This is only file-level precision (the line is the first JSX call in the body), tagged confidence: 'passthrough' with passthroughReason: 'function-body-source'. The assistant reads the file to find the exact line.

React Server Components (Next.js App Router)

JSX in files without 'use client' renders on the server and reaches the browser with no source information. The browser-side component tree only sees the nearest 'use client' boundary, so the scan cannot map those issues to the file that wrote them. It finds the nearest thing it can, usually a wrapper such as <ThemeProvider>.

Each source match therefore carries a confidence:

  • 'high': the match is the real source. Propose fixes normally.
  • 'passthrough': the match is a wrapper, provider, or cloneElement shim and probably not the real source. passthroughReason says why (no-named-component-in-walk, children-passthrough-line, context-provider-line, cloneElement-call-line, owner-stack-cap), so the assistant can warn you precisely.

To get exact sources for a server component, add 'use client' to its file so it renders in the browser.

Gate automated fix flows on summary.failuresWithSourceHighConfidence. summary.failuresWithSource includes passthrough matches and can look healthy even when most point at the wrong file.

When this tool is not a good fit

If your project is mostly one of these, expect few useful code changes:

  • Not React (Vue, Svelte, Angular, Solid, plain HTML). Scans still run and report issues, but every issue lands in unmapped because there is no React component tree to walk, and without that anchor source maps cannot help either. Adapters for other frameworks are on the roadmap.
  • Content from a CMS (Storyblok, Contentful, Sanity, Optimizely, Builder.io). Alt text, headings, and link names written in a CMS live in the CMS, not in your code. These issues are tagged confidence: 'passthrough' with passthroughReason: 'cms-rendered-content:<CMS>', and the fix flow points you to the CMS admin instead of proposing a code change.
  • Production or minified builds. The dev-only React transform is what records source locations. If your production bundle ships source maps, path 6 above recovers the source, tagged passthrough with component-function-location, and the assistant shows a warning per row. Without source maps, every issue is unmapped and sourceMappingDiagnostics.reactDevTransformMissing is set so the assistant reports that source mapping isn't available for that page.
  • Third-party iframes (ReCAPTCHA, HubSpot, Intercom, Drift, Optimizely banners). That content is rendered by code you do not own. Issues land in thirdPartyIframe; the fix is a vendor change or AudioEye's runtime fixes, not a code change.
  • Shadow DOM. Open shadow roots are scanned, nested ones included, and their issues land in shadowDom with a selector that chains each host with >>> (for example div#widget >>> button). Closed shadow roots cannot be entered, and the React tree does not reach into shadow content.
  • React Server Components without 'use client'. See above. Most issues come back as passthrough with no-named-component-in-walk: a useful signal, not a code change. Source maps do not help here because the missing piece is the server-side component tree.

Roadmap

  • Source mapping for more frameworks. See docs/framework-support.md. Today only React is supported. Preact, SolidJS, Inferno, Vue, Svelte, and Angular are planned through a pluggable adapter API with per-project framework caching.

Privacy Policy

The server sends your AudioEye sign-in and license credentials to AudioEye's API for device-pairing sign-in and license validation; a validated license is cached locally for a grace period, so not every scan contacts AudioEye. The update check calls the npm registry configured for @audioeye (npmjs by default); if your npm config (.npmrc files, npm_config_* environment variables, or NPM_TOKEN for GitHub Packages) holds a token for npmjs or GitHub Packages, that token is sent to that registry only. The browser the server launches loads the pages you scan and their source maps like a normal browser visit. Scan results, page facts, and source excerpts are returned to the MCP client you run the server in (for example Claude), which handles them under its own privacy terms. Nothing else leaves your machine. AudioEye's handling of the data it receives is described in the AudioEye Privacy Policy.

License

Proprietary. See LICENSE. The SDK and its source are not open source; use is subject to AudioEye's terms of service or your separate agreement with AudioEye.

FAQs

Package last updated on 02 Oct 2026

Related posts