Skip to main content
Glama

@icjia/axecap

A lightweight local MCP server that runs axe-core accessibility audits via Playwright and returns compressed, actionable results optimized for Claude's context window. Where lightcap wraps Lighthouse (which embeds axe-core behind several layers of abstraction), axecap runs axe-core directly — giving full control over WCAG conformance level targeting (A, AA, AAA), rule selection, and element-level detail that Lighthouse filters or aggregates away.

Why?

A raw axe-core result object can be 50K-500K tokens — deeply nested JSON with HTML snippets, full DOM node references, related nodes, and verbose check arrays. AxeCap compresses that into ~30-150 lines of structured plain text that Claude can read and act on immediately.

The workflow that matters:

You: "Audit localhost:3000 for WCAG AA"
Claude: [calls audit_url] 14 violations (3 critical, 5 serious, 4 moderate, 2 minor)
Claude: "I see 3 critical violations. Let me fix them now."
Claude: [edits your source files]
You: "Run it again"
Claude: [calls audit_url] 6 violations (0 critical, 2 serious, 3 moderate, 1 minor)

This audit → fix → re-audit loop is what makes an MCP server more valuable than the axe-core CLI.

Related MCP server: A11y MCP Server

Why not just use lightcap?

lightcap is the right tool when you want a holistic Lighthouse audit (performance + a11y + SEO + best practices). But lightcap's accessibility results come from Lighthouse's interpretation of axe-core, which:

  1. Filters rules — Lighthouse includes ~40 of axe-core's ~90+ rules, dropping many AAA and best-practice rules

  2. Loses granularity — Lighthouse aggregates axe results into its own scoring system; individual rule metadata (tags, impact, help URLs) is partially stripped

  3. Cannot target conformance levels — you can't ask Lighthouse for "AAA only" or "just the delta between AA and AAA"

  4. Merges axe-core's incomplete category into passes — axe-core distinguishes "passed," "failed," and "needs review" (incomplete); Lighthouse collapses the third

axecap solves all four. It's the precision tool for WCAG compliance work; lightcap is the broad-spectrum audit tool.

When to use which

Scenario

Tool

Pre-deploy check (perf + a11y + SEO)

lightcap run_audit

Quick a11y score with impact grouping

lightcap run_a11y

Targeted WCAG AA compliance audit

axecap audit_url

AAA gap analysis (what would it take?)

axecap audit_url with level: 'aaa', delta: true

Audit specific rules (e.g., color-contrast only)

axecap audit_url with rules filter

Get detailed rule documentation mid-fix

axecap get_rule_info

Look up which rules map to a WCAG criterion

axecap get_rules

Multi-site performance + a11y sweep

lightcap run_audit

Test a component's HTML without a server

axecap audit_html

What it does

  • Runs axe-core audits directly (not through Lighthouse) for full rule-set access

  • Targets WCAG conformance levels: A, AA (default), AAA, or best-practice

  • Layers best-practice and experimental rule sets on top of any level (bestPractices / experimental — the axe DevTools extension toggles)

  • AAA delta mode shows only the gap from AA to AAA ("what would it take?")

  • Audits specific axe-core rules by ID (e.g., color-contrast, image-alt)

  • Audits raw HTML content without a running server (component testing)

  • Compresses ~50K-500K token axe-core JSON into ~30-150 lines of structured plain text

  • Groups violations by impact: critical, serious, moderate, minor

  • Includes WCAG criteria + conformance level per violation (e.g., [1.4.3 AA])

  • Includes Deque University help URLs per violation

  • Includes "needs review" (incomplete) results as opt-in

  • Queries axe-core's rule registry without launching a browser (instant response)

  • Waits for SPA elements before auditing (waitFor parameter)

  • Optionally saves full JSON results to disk for manual review

  • Reports server, axe-core, and Playwright version info with npm update availability

  • Standalone CLI for use outside of MCP clients

  • Runs as a local MCP server over stdio (no HTTP, no ports, no remote attack surface)

Installation

Prerequisites

  • Node.js >= 18 (check with node --version)

  • Claude Code, Cursor, or any MCP-compatible client (for MCP mode)

Playwright downloads Chromium automatically on first install — no separate browser install needed.

npx downloads and runs the package automatically. Nothing to install globally.

# Test that it works
npx -y @icjia/axecap --help

Option 2: Global install

npm install -g @icjia/axecap

Option 3: Clone for development

git clone https://github.com/ICJIA/axecap-mcp.git
cd axecap-mcp
npm install
npx playwright install chromium

Setup with Claude Code

Claude Code manages MCP server lifecycle automatically — you register the server once, and Claude Code starts/stops it with each session.

# Register for all projects (user-level)
claude mcp add axecap -s user -- npx -y @icjia/axecap

# Or register for current project only
claude mcp add axecap -s project -- npx -y @icjia/axecap

Using a local clone

# Point directly at the source (for development)
claude mcp add axecap -s user -- node /absolute/path/to/axecap-mcp/src/server.js

Manual config (edit settings.json directly)

If you prefer, edit ~/.claude/settings.json:

{
  "mcpServers": {
    "axecap": {
      "command": "npx",
      "args": ["-y", "@icjia/axecap"]
    }
  }
}

Verify it's registered

Restart Claude Code after registering. You should see axecap listed when you run /mcp in Claude Code. Then test:

"Use axecap to audit http://localhost:3000 for WCAG AA"

Tool routing with lightcap, viewcap, and Chrome MCP

If you have lightcap, viewcap, and Chrome MCP registered alongside axecap, add this to your project's CLAUDE.md to ensure Claude uses the right tool for each task:

# Tool preferences
- For WCAG compliance audits (A/AA/AAA, specific rules, rule lookups), use the `axecap` MCP server (audit_url, audit_html, get_rules, get_rule_info, get_status).
- For Lighthouse audits (performance, accessibility, SEO, best practices), use the `lightcap` MCP server (run_audit, run_a11y, get_status).
- For all screenshots, use the `viewcap` MCP server (take_screenshot, capture_selector, take_screencast).
- For version info on MCP tools, use the relevant server's `get_status` tool.
- Use Chrome MCP for browser automation, DOM interaction, and navigation only.

Setup with Cursor

Cursor supports MCP servers through its settings. Add axecap to your Cursor MCP configuration.

Global configuration

Edit ~/.cursor/mcp.json (create it if it doesn't exist):

{
  "mcpServers": {
    "axecap": {
      "command": "npx",
      "args": ["-y", "@icjia/axecap"]
    }
  }
}

Project-level configuration

Create .cursor/mcp.json in your project root:

{
  "mcpServers": {
    "axecap": {
      "command": "npx",
      "args": ["-y", "@icjia/axecap"]
    }
  }
}

After adding the configuration, restart Cursor. AxeCap's tools will be available to the AI assistant.

Setup with other MCP clients

AxeCap works with any MCP client that supports stdio transport. The server communicates over stdin/stdout using JSON-RPC (the MCP protocol). Configure your client to spawn:

npx -y @icjia/axecap

No HTTP ports, no environment variables, no API keys required.

MCP Tools

audit_url

Run an axe-core accessibility audit on a web page at a specified WCAG conformance level. Default audits A + AA rules (cumulative). Set bestPractices / experimental to layer those rule sets on top of the level — together they reproduce the axe DevTools extension's two toggles (level: 'aa', bestPractices: true, experimental: true matches a "WCAG 2.1 AA + Best Practices + Experimental" extension scan).

Parameter

Type

Default

Description

url

string

(required)

HTTP/HTTPS URL to audit

level

string

'aa'

WCAG conformance level: 'a', 'aa', 'aaa', 'best-practice'

bestPractices

boolean

false

Also run best-practice rules on top of the level (axe DevTools "Best Practices" toggle)

experimental

boolean

false

Also run experimental rules on top of the level (axe DevTools "Experimental" toggle)

delta

boolean

false

If true with level: 'aaa', show only AAA-specific violations

rules

string[]

Run only these specific rule IDs (e.g., ['color-contrast', 'image-alt'])

maxViolations

number

10

Top N violations per impact group (max 15)

viewport

string

'desktop'

'desktop' or 'mobile'

includeIncomplete

boolean

false

Include "needs review" results

waitFor

string

CSS selector to wait for before auditing (for SPAs)

directory

string

Save full JSON results to this directory

Returns: Compressed plain text with violation count, impact grouping, WCAG criteria, CSS selectors, and help URLs.

Example output (page with violations at AA):

axe: http://localhost:3000 [desktop] AA — 14 violations (3c 5s 4m 2n)

── Critical (3 violations, 18 el) ──
  ✗ image-alt [1.1.1 A] (12 el)
    → img.hero-image
    → img.card-thumb (×8)
    → img.logo
    → img.partner-logo (×2)
    → (+7)
    ℹ https://dequeuniversity.com/rules/axe/4.10/image-alt
  ✗ color-contrast [1.4.3 AA] (4 el)
    → p.subtitle
    → span.caption
    → a.nav-link
    → (+1)
    ℹ https://dequeuniversity.com/rules/axe/4.10/color-contrast
  ✗ label [1.3.1 A] (2 el)
    → input#search
    → input#email
    ℹ https://dequeuniversity.com/rules/axe/4.10/label

── Serious (5 violations, 11 el) ──
  ✗ heading-order [1.3.1 A] (1 el)
    → section.content > h4
    ℹ https://dequeuniversity.com/rules/axe/4.10/heading-order
  ✗ link-name [2.4.4 A] (3 el)
    → a.icon-link, a.social-fb, a.social-tw
    ℹ https://dequeuniversity.com/rules/axe/4.10/link-name
  ...

── Moderate (4 violations, 8 el) ──
  ...

── Minor (2 violations, 3 el) ──
  ...

Example output (clean page):

axe: http://localhost:3000 [desktop] AA — 0 violations

One line. ~20 tokens. No wasted context on a page that doesn't need fixing.

Example output (AAA delta):

axe: http://localhost:3000 [desktop] AAA (delta from AA) — 6 violations (0c 2s 3m 1n)

── Serious (2 violations, 5 el) ──
  ✗ link-in-text-block [1.4.1 A] (3 el)
    → a.inline-link (×3)
    ℹ https://dequeuniversity.com/rules/axe/4.10/link-in-text-block
  ...

audit_html

Run an axe-core audit on raw HTML content. Useful for testing components or generated markup without a running server. All network requests from embedded resources are blocked (SSRF-safe).

Parameter

Type

Default

Description

html

string

(required)

HTML content to audit

level

string

'aa'

WCAG conformance level

bestPractices

boolean

false

Also run best-practice rules on top of the level

experimental

boolean

false

Also run experimental rules on top of the level

rules

string[]

Specific rule IDs to run

maxViolations

number

10

Top N per impact group

viewport

string

'desktop'

'desktop' or 'mobile'

includeIncomplete

boolean

false

Include needs-review results

Returns: Same compressed format as audit_url.

get_rules

List axe-core rules, optionally filtered by WCAG level or tag. Does not require a browser — instant response.

Parameter

Type

Default

Description

level

string

Filter to rules at this WCAG level ('a', 'aa', 'aaa')

criterion

string

Filter to rules for a specific WCAG criterion (e.g., '1.4.3')

search

string

Search rule IDs and descriptions (substring match)

Example output:

axe-core rules (AA, 47 rules):

  color-contrast [1.4.3 AA] serious — Elements must meet minimum color contrast ratio thresholds
  image-alt [1.1.1 A] critical — Images must have alternate text
  label [1.3.1 A] critical — Form elements must have labels
  link-name [2.4.4 A] serious — Links must have discernible text
  ...

get_rule_info

Get detailed information about a specific axe-core rule.

Parameter

Type

Default

Description

ruleId

string

(required)

axe-core rule ID (e.g., 'color-contrast')

Example output:

axe rule: color-contrast
  Impact:    serious
  WCAG:      1.4.3 (AA)
  Tags:      wcag2aa, wcag143, cat.color
  Help:      Elements must meet minimum color contrast ratio thresholds
  Help URL:  https://dequeuniversity.com/rules/axe/4.10/color-contrast

get_status

Returns server version, axe-core version, Playwright version, and update availability.

The "update available" check runs npm view axe-core version, a one-time network call at server startup (5s timeout, non-blocking). Offline or behind a firewall it simply reports (latest) — no audit functionality depends on it.

Parameter

Type

Default

Description

(none)

No parameters

Example output:

axecap status
  Server:     @icjia/axecap v0.1.0
  axe-core:   v4.10.2 (latest: v4.10.2)
  Playwright: v1.49.1
  Node:       v22.22.0
  Platform:   darwin arm64

WCAG Conformance Level Targeting

This is the core differentiator from lightcap. WCAG conformance is cumulative: AAA includes all AA rules, which include all A rules. The level parameter handles this automatically — you don't need to think about tag composition.

level param

What it audits

'a'

Level A only

'aa' (default)

A + AA (everything AA compliance requires)

'aaa'

A + AA + AAA (full conformance)

'best-practice'

Best practices only (not WCAG-mapped)

Delta mode

For "what would it take to go from AA to AAA?", pass level: 'aaa' and delta: true. This returns only AAA-specific violations — the gap between your current AA compliance and full AAA conformance.

CLI (standalone usage)

AxeCap includes a standalone CLI for use outside of MCP clients:

# Install globally (or use npx)
npm install -g @icjia/axecap

# WCAG AA audit (default)
axecap audit http://localhost:3000

# WCAG AAA audit
axecap audit http://localhost:3000 --level aaa

# AAA delta (only AAA-specific violations)
axecap audit http://localhost:3000 --level aaa --delta

# Specific rules only
axecap audit http://localhost:3000 --rules color-contrast,image-alt

# Include "needs review" results
axecap audit http://localhost:3000 --include-incomplete

# Mobile viewport
axecap audit http://localhost:3000 --viewport mobile

# Wait for SPA element before auditing
axecap audit http://localhost:3000 --wait-for "#app-loaded"

# Save full JSON to directory
axecap audit http://localhost:3000 --directory ~/reports

# List AA rules
axecap rules --level aa

# Rules for a specific WCAG criterion
axecap rules --criterion 1.4.3

# Search rules
axecap rules --search contrast

# Rule detail
axecap rule-info color-contrast

# Check versions
axecap status

# Verbose logging
axecap --verbose audit http://localhost:3000

When run without a subcommand, axecap starts in MCP server mode (stdio transport).

Usage examples

From Claude Code or Cursor, just ask naturally:

"Audit localhost:3000 for WCAG AA"
"Audit localhost:3000 for AAA and show only the delta from AA"
"Audit localhost:3000 with axecap, rules: aria-allowed-role"
"What axe-core rules cover WCAG criterion 1.4.3?"
"Get info on the color-contrast rule"
"Audit this HTML for accessibility: <img src='photo.jpg'>"
"What version of axecap is running?"
"Fix all critical and serious violations, then re-audit"

Compression strategy

The central design principle: zero tokens on passes, maximum detail on failures.

Every tool response must be small enough that Claude retains room to reason and act. A raw axe-core result object can be 50K-500K tokens. AxeCap compresses that to ~20-2,000 tokens depending on the number of violations.

Context window impact

Scenario

Lines

Tokens (~)

vs. Raw JSON

Clean page (0 violations)

1

~20

99.99% smaller

Page with 5 violations

~20-30

~500

99.90% smaller

Heavy violation page (30+ rules)

~80-150

~2,000

99.60% smaller

Rule info lookup

~10-15

~200

Rule list (filtered)

~20-40

~600

Raw axe-core JSON (NEVER returned)

~5K-50K

~50K-500K

How compression works

axe-core returns deeply nested JSON with HTML snippets, full DOM node references, related nodes, and verbose any/all/none check arrays. The compression engine applies:

  1. Violations only by default — passes and inapplicable rules skipped entirely (zero tokens)

  2. Incomplete (needs-review) as opt-in — returned only when includeIncomplete: true

  3. Compact header — URL, conformance level, violation count, impact summary on one line

  4. Impact grouping — critical/serious/moderate/minor with shorthand: 3c 5s 4m 2n

  5. CSS selectors only — no HTML snippets, no full DOM node trees

  6. Selector deduplicationimg.card (x8) not eight separate entries

  7. Selector truncation — capped at 60 chars

  8. Selector sanitization — non-CSS characters stripped to prevent prompt injection

  9. WCAG tags extractedwcag111 -> 1.1.1, with conformance level: [1.1.1 A]

  10. Top N violations per impact group — configurable, default 10

  11. Tiered element detail — critical/serious show 5 elements, moderate/minor show 3

  12. Help URL included per rule — one-line Deque University reference link

  13. Hard cap — 200 lines / 50,000 chars

What is never returned: raw axe JSON, full HTML snippets, DOM node trees, related node arrays, any/all/none check detail, inapplicable rules.

Why plain text, not JSON?

JSON wastes tokens on syntax ({, }, "key":, quotes). Plain structured text is ~30% fewer tokens than equivalent JSON, easier for Claude to scan, and still structured enough to act on.

Testing

# Run all tests
npm test

# Run a specific test file
node --test test/compress.test.js

The test suite covers:

  • URL validation — scheme whitelist, blocking of file:/data:/javascript:/ftp: schemes

  • Metadata endpoint blocking — AWS, GCP, Azure cloud metadata endpoints

  • IP blocking — localhost bypass, full 127.x loopback range, all RFC1918 172.16-31.x ranges

  • waitFor validation — CSS-only enforcement, blocking of text=/xpath=/>> pseudo-selectors

  • Sanitization — control char stripping, newline removal, zero-width char removal, CSS-safe selector filtering

  • Compression — impact grouping, WCAG criterion extraction, selector deduplication, tiered element detail, delta mode filtering, output line + char limits

  • Rule queries — level filtering, criterion filtering, search, rule info lookup

  • Error sanitization — known-safe passthrough, connection/timeout/DNS mapping, path leakage prevention

  • Config sanity — all numeric limits positive, WCAG level tag cumulation, security constants

Local development

There is no build step. AxeCap is plain JavaScript with ES modules. The source files are what ships to npm.

Edit source files
      |
      v
Restart Claude Code (re-spawns the server from source)
      |
      v
Test by talking to Claude Code ("audit localhost:3000 for WCAG AA")
      |
      v
See a bug? Edit the file, restart Claude Code, repeat.

Quick development setup

# 1. Clone and install
git clone https://github.com/ICJIA/axecap-mcp.git
cd axecap-mcp
npm install
npx playwright install chromium

# 2. Register your local copy with Claude Code
claude mcp add axecap -s user -- node $(pwd)/src/server.js

# 3. Restart Claude Code

# 4. Spin up a test target in another terminal
npx serve -l 3000 .

# 5. Test from Claude Code:
#    "Use axecap to audit http://localhost:3000 for WCAG AA"
#    "Audit localhost:3000 for AAA and show only the delta from AA"
#    "What axe-core rules cover WCAG criterion 1.4.3?"

After editing source files, restart Claude Code to pick up changes (the server is re-spawned fresh each startup).

Architecture

src/
├── server.js ........... MCP server init + 5 tool registrations + version tracking
├── runner.js ........... Playwright launch + axe-core injection + URL/directory validation
├── compress.js ......... axe results → compressed plain text (the core of the server)
├── rules.js ............ axe-core rule registry queries (metadata, tags, filtering)
├── cli.js .............. Commander-based standalone CLI
└── config.js ........... Constants, WCAG level tags, logging helper

File

Role

server.js

MCP init, Zod schemas for 5 tools, request routing, error handling

runner.js

Playwright lifecycle, axe-core injection via page.evaluate(), URL validation (scheme whitelist, IP resolution, metadata blocklist), directory validation (symlink-aware), waitFor validation

compress.js

compressResults() — impact grouping + WCAG refs + element dedup + help URLs; formatRuleList() / formatRuleInfo() — rule registry formatting

rules.js

getRules() and getRuleInfo() — queries axe-core's built-in rule registry without launching a browser

cli.js

audit, rules, rule-info, status subcommands; falls back to MCP server mode when no subcommand given

config.js

CONFIG object with all limits/thresholds/WCAG tags, log(level, msg) helper, setVerbosity()

Dependencies

Package

Purpose

@modelcontextprotocol/server

MCP server SDK (stdio transport, tool registration)

axe-core

Deque axe-core accessibility engine (MPL 2.0) — injected into page context

playwright

Browser automation (launches Chromium, navigates, runs page.evaluate)

commander

CLI subcommand parsing

zod

Schema validation for MCP tool parameters

Not needed (unlike lightcap):

  • No lighthouse — axe-core is the engine

  • No chrome-launcher — Playwright manages Chromium

  • No sharp — no image processing

  • No @axe-core/playwright — we inject axe.source directly for full control

Security

AxeCap runs locally over stdio — no network listener, no ports, no remote attack surface. Security mitigations focus on preventing SSRF, prompt injection, and resource exhaustion.

SSRF prevention

  • Scheme whitelist: Only http: and https: URLs are allowed. file://, data:, javascript:, ftp://, and all other schemes are blocked.

  • Metadata / unspecified-address blocklist: AWS (169.254.169.254), GCP (metadata.google.internal), Azure (metadata.azure.com), and the unspecified addresses 0.0.0.0 and [::] are blocked by hostname. Genuine loopback (localhost, 127.0.0.1, ::1) remains allowed so local dev servers can be audited; the "all interfaces" addresses are treated as blocked, not as loopback.

  • Private IP range blocklist: All RFC1918 ranges (10.x, 172.16–31.x, 192.168.x), full loopback (127.x), "this network" (0.x), CGNAT shared space (100.64.0.0/10, RFC6598), IPv4 link-local (169.254.x), IPv6 link-local (fe80::/10), IPv6 unique-local (full fc00::/7 — both the fc and fd halves), and IPv6 unspecified/loopback (::, ::1) are blocked.

  • IPv6-mapped IPv4 normalization: Addresses like ::ffff:169.254.169.254 are normalized before classification.

  • Multi-address DNS check: Hostnames are resolved with { all: true } and blocked if any returned address is private — defends against hosts that publish a mix of public and internal records.

  • Fail-closed DNS: If hostname resolution fails, the request is blocked (not allowed).

  • Post-navigation URL recheck: After Playwright navigates, page.url() is validated against the same blocklist — catches HTTP redirect chains and DNS rebinding attacks.

  • Sub-resource filtering (audit_url): The loaded page's own requests (images, scripts, fetch) are intercepted; any request to a metadata endpoint or private IP literal is aborted, so an audited page cannot reach the cloud metadata service or probe the LAN. Public resources (CDNs) and loopback are allowed, matching the navigation policy.

  • HTML audit network blocking: audit_html blocks all network requests via page.route('**/*', route => route.abort()), preventing SSRF via embedded resources like <img src="http://169.254.169.254/...">.

Known limitation: DNS for hostnames is resolved once at validation time, not re-checked at connection time, and sub-resource hostnames are not re-resolved. A determined DNS-rebinding attacker controlling a domain could still target their own internal network; the metadata/private-IP-literal blocks above are the primary defense.

Prompt injection prevention

  • Output sanitization: All page-controlled content (CSS selectors, rule IDs) is stripped of control characters (C0/C1), newlines, zero-width chars, and BOM before being included in output.

  • CSS-safe selector sanitization: Selectors are additionally stripped of non-CSS characters, blocking crafted class names designed to inject instructions.

  • Selector truncation: CSS selectors are capped at 60 characters.

  • Help text truncation: Help text capped at 120 characters.

  • Character budget: Total output is capped at 50,000 characters (in addition to the 200-line cap).

  • HTML snippets never returned: axe-core's node.html field (contains raw page HTML) is never included in output — CSS selectors only.

  • Dialog auto-dismiss: page.on('dialog', ...) dismisses alert/confirm/prompt dialogs that could block execution.

waitFor selector validation

The waitFor parameter is restricted to CSS selectors only. Playwright pseudo-selectors (text=, xpath=, >>, css=, _react=, _vue=) are blocked.

Directory traversal prevention

  • Output paths are validated against the user's home directory and /tmp only.

  • The deepest existing ancestor directory is resolved via realpathSync before any new directories are created, preventing TOCTOU symlink swap attacks.

  • After creation, the final path is re-verified against allowed roots (belt and suspenders).

Error message safety

  • Error messages returned to the AI are sanitized through an allowlist. Known safe messages pass through; common error types (connection refused, timeout, DNS failure) are mapped to generic messages; unknown errors return 'Audit failed' with details logged to stderr only.

Resource limits

Resource

Limit

Enforced By

Concurrent audits

2 max

runner.js (slot gate, fail-fast beyond)

Page load timeout

30s

Playwright goto options

axe-core execution timeout

30s

page.evaluate timeout

Total audit timeout

60s

Promise.race in runner.js

URL length

2048 chars

Zod schema

HTML input length

500KB

Zod schema

Directory path length

500 chars

Zod schema

Violations per impact group

15 max

Zod schema + compress.js

Elements per violation

5 shown

compress.js

Selector length

60 chars

compress.js

Help text length

120 chars

compress.js

Output lines

200 max

compress.js

Output characters

50,000 max

compress.js

Browser process

killed in finally

runner.js

No raw data exposure

Full axe-core JSON is never returned to Claude. JSON can only be saved to disk (for human review) via the directory parameter. The compression engine is the only path from axe-core results to Claude's context.

Configuration flags

Flag

Description

--verbose

Log audit timing, browser lifecycle, compression details

--quiet

Log errors only

ICJIA-specific usage

ADA Title II compliance (April 24, 2026 deadline)

The audit → fix → re-audit loop is the primary workflow:

You: "Audit localhost:3000 for WCAG AA with axecap"
You: "Fix all critical and serious violations"
You: "Run it again — how many violations remain?"
You: "Now show me what AAA violations exist (delta mode)"
You: "Which of those are feasible to fix?"

The sia-r110 problem

For pages flagged with "All roles are invalid" from Vuetify's auto-generated role attributes:

You: "Audit localhost:3000 with axecap, rules: aria-allowed-role"

This runs only the relevant rule, returning exactly the elements with invalid roles. lightcap can't do this.

Pre-deploy checks

Add to your project's CLAUDE.md:

# Deploy checklist
Before any deploy to production:
1. Run `axecap audit_url` against localhost with level AA
2. Verify 0 critical violations and 0 serious violations
3. Run `lightcap run_audit` for performance + SEO baseline

Clean-room notice

This project's design is informed by axe-core's public documentation, API, and rule registry. This is an original implementation. axe-core is used as a library dependency (Mozilla Public License 2.0). Playwright is used for browser automation (Apache 2.0). No code from third-party axe wrapper packages (e.g., @axe-core/cli, @axe-core/playwright, accessibility-checker) is used.

License

MIT. See LICENSE.

Available Tools

5 tools
audit_htmlA

Run an axe-core audit on raw HTML content. Useful for testing components or generated markup without a running server. Network requests from embedded resources are blocked.

ParametersJSON Schema
NameRequiredDescriptionDefault
htmlYesHTML content to audit
levelNoWCAG conformance level (default: aa)
rulesNoSpecific axe-core rule IDs to run
viewportNoViewport emulation (default: desktop)
maxViolationsNoTop N per impact group (default 10)
includeIncompleteNoInclude needs-review results

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the transparency burden. It discloses a meaningful behavior (network requests blocked) but doesn't describe the return format or whether scripts in the HTML execute. It doesn't contradict annotations, and the audit verb implies non-mutating behavior, but more detail would help.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the action and resource. Every phrase contributes: purpose, use case, and a key behavioral constraint. No filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description explains the purpose, the offline context, and a key limitation. With the schema fully documenting all parameters, this is reasonably complete for an audit tool. The main omission is an explicit description of the return value or report structure, but the core usage is well covered.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description reinforces the 'html' parameter with 'raw HTML content' but adds no additional parameter semantics beyond what the schema already provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Run an axe-core audit on raw HTML content.' It clearly distinguishes itself from the sibling tool audit_url by emphasizing raw HTML input rather than a URL.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives a clear use case: 'Useful for testing components or generated markup without a running server.' The network-blocking limitation also helps decide when to use this tool versus a URL-based audit. It doesn't explicitly name an alternative, so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

audit_urlA

Run an axe-core accessibility audit on a web page at a specified WCAG conformance level. Default audits A + AA rules (cumulative). Returns violations grouped by impact with WCAG criteria, CSS selectors, and help URLs.

ParametersJSON Schema
NameRequiredDescriptionDefault
urlYesHTTP or HTTPS URL to audit
deltaNoIf true with level aaa, show only AAA-specific violations (the gap from AA to AAA)
levelNoWCAG conformance level — aa (default) audits A + AA rules; aaa audits A + AA + AAA
rulesNoRun only these specific axe-core rule IDs (e.g., ["color-contrast", "image-alt"])
waitForNoCSS selector to wait for before auditing (for SPAs)
viewportNoViewport emulation (default: desktop)
directoryNoSave full JSON results to this directory
maxViolationsNoTop N violations per impact group (default 10, max 15)
includeIncompleteNoInclude needs-review results in addition to violations

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the burden of disclosing behavior. It adds meaningful details: default audit level (A+AA cumulative), output grouping by impact, and inclusion of WCAG criteria, CSS selectors, and help URLs. This goes beyond a generic statement but does not cover potential errors or access limitations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tight sentences: the first states purpose, the second explains default behavior and return format. Zero filler, well-structured, and front-loaded with the core function.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no output schema, the description explains return composition (violations grouped by impact with WCAG criteria, CSS selectors, help URLs). It does not discuss error cases or relationship to sibling tools, but with 9 richly described parameters and a clear summary, it is reasonably complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3. The description does not add extra parameter semantics beyond what the schema already provides, but it does mention the default level (aa), which aligns with the schema. No additional value beyond schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool 'Run an axe-core accessibility audit on a web page at a specified WCAG conformance level.' This specifies the verb (run), resource (web page), and distinguishes it from siblings like audit_html (which likely audits HTML input) and get_rules (lists rules).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage for auditing web pages but does not explicitly say when to use this tool versus alternatives like audit_html or get_rules. No exclusions or conditions are given, so the usage context is clear but not fully articulated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_rule_infoA

Get detailed information about a specific axe-core rule including WCAG criteria, impact, tags, and help URL.

ParametersJSON Schema
NameRequiredDescriptionDefault
ruleIdYesaxe-core rule ID (e.g., "color-contrast")

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the burden of disclosing behavior. It does disclose the return value content (WCAG criteria, impact, tags, help URL), which is useful. However, it doesn't mention error handling (e.g., invalid ruleId), side effects, or whether any permissions are needed. As a read-only getter, the absence of side-effect information is less critical, but it's still a gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, front-loaded sentence that immediately states the action and resource, then lists key information returned. Every word contributes value with no filler or repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

This is a simple tool with one parameter and no output schema, so the description adequately explains what the tool does and what the return contains. It could mention behavior for a non-existent ruleId, but for a straightforward getter, the description is sufficiently complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema covers 100% of parameters with a helpful description for ruleId (including an example). The tool description only restates the concept of a specific axe-core rule without adding new details beyond the schema. Baseline 3 is appropriate since schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb "Get" and clearly identifies the resource as "detailed information about a specific axe-core rule," listing the included content (WCAG criteria, impact, tags, help URL). This distinguishes it from sibling tools like get_rules and get_status.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage: when you need details for a specific rule, identified by ruleId. It clearly states the tool's scope (specific rule vs. listing all rules with get_rules), though it doesn't explicitly name alternatives or exclusions. This is clear context but not full when-to-use/when-not-to-use guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_rulesA

List axe-core accessibility rules, optionally filtered by WCAG level, criterion, or search term. Does not require a browser — instant response.

ParametersJSON Schema
NameRequiredDescriptionDefault
levelNoFilter to rules at this WCAG level
searchNoSearch rule IDs and descriptions
criterionNoFilter to rules for a WCAG criterion (e.g., "1.4.3")

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the burden of disclosing behavior. It states 'Does not require a browser — instant response', which adds performance and execution context. The word 'List' implies a read-only, non-destructive operation, and 'optionally filtered' clarifies behavior when no filters are supplied. It does not describe return format, but for a simple list tool this is adequate.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single concise sentence that front-loads the core action ('List axe-core accessibility rules'), then adds filter options and a useful behavioral note. No wasted words; every clause earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with 3 optional parameters, no output schema, and no annotations, the description covers the main aspects: what it lists, how to filter, and that it is instant and browserless. It does not mention return structure, but that is not essential for a list operation, and the sibling get_rule_info presumably handles detailed rule information.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, with each parameter (level, search, criterion) having its own description. The tool description adds a summary of filtering ('by WCAG level, criterion, or search term') but no additional detail beyond what the schema provides. This is consistent with the baseline for high schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses the specific verb 'List' with the resource 'axe-core accessibility rules' and mentions optional filtering by WCAG level, criterion, or search term. This clearly distinguishes it from siblings like audit_url/audit_html (which perform audits) and get_rule_info (which focuses on a single rule).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies when to use this tool: to list rules without requiring a browser, providing instant responses. It does not explicitly mention alternatives or when not to use it, but the contrast with browser-requiring audit tools is implicit. The lack of explicit exclusions keeps it from a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_statusA

Returns axecap server version, installed axe-core version, Playwright version, and whether a newer axe-core version is available on npm.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A3.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the burden of behavioral disclosure. It accurately lists all return values, but it does not explicitly state that the tool is read-only or that checking via npm involves an external network request. For a simple informational tool, this is adequate but not rich in behavioral context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single, front-loaded sentence efficiently lists all return values with no fluff or repetition. Every word earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

This is a simple, parameterless tool with no output schema. The description fully enumerates the return values, making it complete for its intended purpose.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so per the rubric, the baseline is 4. The description adds no parameter details, but none are needed since the input schema is empty.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool returns specific status information (server version, axe-core version, Playwright version, npm availability check). This distinguishes it from sibling audit and rule tools, which focus on different resources.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives no explicit guidance on when to use this tool versus alternatives. While the name and content imply it is for checking versions/status, there is no stated context, prerequisites, or mention of alternative tools for other purposes.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

TDQS

A4.3/5.0
Disambiguation5/5

Each tool has a clearly distinct purpose: auditing a URL, auditing HTML, listing rules, getting rule details, and checking server status. There is no overlap or ambiguity between them.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern using underscores (audit_url, audit_html, get_rules, get_rule_info, get_status). The naming is uniform and predictable.

Tool Count5/5

With 5 tools, the set is well-scoped for an accessibility auditing server. Each tool serves a necessary function without redundancy or bloat.

Completeness5/5

The tool set covers the core domain: performing audits on both live URLs and raw HTML, accessing comprehensive rule information, and checking server status. There are no obvious gaps in the workflow.

Maintenance

ActivityMaintained
ResponsivenessSyncing

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    D
    maintenance
    An MCP (Model Context Protocol) server for performing accessibility audits on webpages using axe-core. Use the results in an agentic loop with your favorite AI assistants (Cline/Cursor/GH Copilot) and let them fix a11y issues for you!
    2
    174
    51
    Mozilla Public 2.0

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ICJIA/axecap-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server