@audioeye/testing-sdk-mcp
v6.2.0
Published
Scans live pages with the AudioEye rules engine and maps accessibility issues to JSX source.
Readme
@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 setupThis 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
VS Code (GitHub Copilot and other MCP features built into 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@audioeyePlugin 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@latestClaude 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 loginnpx -y @audioeye/testing-sdk-mcp@latest whoamishows 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 logoutremoves 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__fixproposes 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 withnpx, which runs from the folder your host opened and reads that folder'spackage.json. If itsoverridesconflict 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 thepackage.jsonfixed (the same conflict breaksnpm installthere). An.npmrcin that folder (or your home directory) that points the@audioeyescope 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
npxof whichever Node your login PATH selects (nvm, Volta, and similar tools each bring their own). Check withnpx -y @audioeye/testing-sdk-mcp@latest --versionin 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 useoutput) corrupts the MCP stream. Guard those lines withcase $- in *i*) … ;; esac(bash),[[ -o interactive ]] && [[ -t 1 ]](zsh), orstatus 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 nothingPick 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--globalto keep it available in every project, for example:npx -y @audioeye/testing-sdk-mcp@latest setup --claude --global--globalregisters Claude Code at user scope (and updates~/.claude/settings.json), VS Code in your user profilemcp.jsonrather 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-detectedonly with--global, sosetupnever writes into a project by accident.What it writes: for Claude Code, Codex, and Gemini it runs that host's own
mcp addcommand, 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 theaudioeyeentry and never writes secrets. For Codex it also setsstartup_timeout_sec = 60on that entry (Codex's default is 10 s, which a firstnpxstart can exceed while it downloads the package); a larger value you already set is kept, andcodex mcp addhas no flag for it, sosetupwrites the key into~/.codex/config.tomlafter 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@latestfor Claude Code, Cursor, VS Code, Windsurf, Zed and Gemini, which resolvenpxfrom your login PATH themselves;--prefix /keeps npx from reading the open workspace'spackage.json, whose conflictingoverrideswould abort the start withEOVERRIDE. Codex alone gets<your shell> -lic 'exec npx --prefix / -y @audioeye/testing-sdk-mcp@latest'on macOS and Linux ($SHELL, or/bin/shwhen unset) andcmd /c npx --prefix / -y @audioeye/testing-sdk-mcp@lateston Windows, because the Codex VS Code plugin starts servers with a bare system PATH wherenpxis missing; a login + interactive shell reads the same profile and rc files as your terminal. Before writing anything,setuprunsnpx --prefix / -y @audioeye/testing-sdk-mcp@latest --versionthrough that login shell and warns when it fails, since Codex would fail the same way and the other hosts need the samenpx. If that check fails,setupprints 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'snode. Ubuntu's and macOS's default login files already do this; if yours does not, add[ -f ~/.bashrc ] && . ~/.bashrcto~/.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 tabaudioeye_open_browseror the firsturlscan 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 asscan-<n>.mdbeside 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 undermetadata[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-rulesversion 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.waitForReadyMsis 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 recordswaitedMsandwaitCapMs; 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 theviewportin effect at scan time; pass it toaudioeye_verify_fixto check a fix at the same size. They also recordscannedAt(ISO-8601 UTC) andsessionId, the server session that ran the scan, so a scan from another session can be told apart. When afileName(a Vite/@fs/…or/src/…dev-server path, a webpack URL, or a plain path) points inside the workspace, the entry also carriesfilePath(absolute) andworkspacePath(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.tsxin two apps), no file is picked: the entry carriescandidates(relative paths) instead, and the Source cell lists them afterambiguous:.fileNameitself 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-serverfileNameas-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_WORKSPACEor the current directory), naming the checkout the file lives in. The result carriesresolvedRoot(the checkout holding the file). When a scan's absolute sources resolve outside the workspace, the scan JSON lists them per checkout insourceRootsand 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 (roleSourcesays whether it came from the accessibility tree or theroleattribute), resolvedaria-*attributes, nearest landmark, nearest focusable ancestor (itsaccessibleNameandrolecome from the browser's accessibility tree), andinheritedAtHidden.nearestLandmarkandnearestFocusableAncestorare 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": falsein.audioeye-mcp.jsonturns 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 CDPRuntime.addBinding, andAudioEyeInspector, 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_IDandAUDIOEYE_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 withSdkLicenseError.
Optional
AUDIOEYE_MCP_PROFILE_DIR: where the browser profile lives. Default~/.cache/audioeye-mcp/profile.AUDIOEYE_MCP_HEADLESS:1ortrueruns 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.jsonlookup. 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/jsxsDEVwrapper 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.cloneElementhook 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.__sourcewhen 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 taggedconfidence: 'passthrough'withpassthroughReason: '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), taggedconfidence: 'passthrough'withpassthroughReason: '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, orcloneElementshim and probably not the real source.passthroughReasonsays 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
unmappedbecause 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'withpassthroughReason: '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
passthroughwithcomponent-function-location, and the assistant shows a warning per row. Without source maps, every issue isunmappedandsourceMappingDiagnostics.reactDevTransformMissingis 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
shadowDomwith a selector that chains each host with>>>(for examplediv#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 aspassthroughwithno-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.
