Skip to main content
Glama

Navable MCP

npm version License: MIT Node.js >= 20

Part of navable.io — open-source accessibility tools for development teams.

A Model Context Protocol (MCP) server that gives AI coding agents real-browser accessibility scanning. Scans localhost pages with Playwright + axe-core (and optionally Pa11y/HTMLCS as a second engine), returns WCAG 2.1 Level A + AA violations with EN 301 549 mapping, and generates structured fix plans your agent can work through autonomously.

Quick Start

  1. Add the MCP config for your editor (see below)

  2. Start your dev server

  3. Ask your agent: "scan http://localhost:3000 for accessibility issues"

Chromium installs automatically on the first scan (~150 MB one-time download). No extra step needed. If auto-install fails (e.g. restricted network), install manually:

npx playwright install chromium

Related MCP server: Accessibility MCP Server

MCP Configuration

Cursor

Add to .cursor/mcp.json:

{
  "mcpServers": {
    "navable": {
      "command": "npx",
      "args": ["-y", "@navable/mcp"],
      "env": {
        "NAVABLE_PROJECT_ROOT": "/absolute/path/to/your/project"
      }
    }
  }
}

NAVABLE_PROJECT_ROOT is optional. Set it if .navable-plan.json is written to the wrong directory (some IDE extension hosts use a different working directory). Omit env if auto-detection works.

VS Code (Copilot)

Add to .vscode/mcp.json:

{
  "servers": {
    "navable": {
      "command": "npx",
      "args": ["-y", "@navable/mcp"]
    }
  }
}

Claude Code

claude mcp add navable -- npx -y @navable/mcp

Available Tools

run_accessibility_scan

Scans a URL for WCAG 2.1 Level A + AA accessibility violations.

By default, only axe-core runs. Pa11y/HTMLCS is opt-in — see engines below.

Input

Description

url

Full URL to scan (e.g. http://localhost:3000)

tags

axe-core rule tags to include (optional)

include

CSS selectors to limit scan scope (optional)

exclude

CSS selectors to exclude (optional)

engines

Engines to run. Default: ["axe"] — only axe-core runs. Pass ["axe", "htmlcs"] to also run Pa11y/HTMLCS. Crossover findings are deduped server-side and tagged alsoFlaggedBy: ["htmlcs"]. Adds ~2–4 s wall-clock per scan. See Scan engines below.

compact

true (default) — smaller JSON: omits description, helpUrl, wcag tags, failureSummary; wcagCriteria keeps only sc and en301549; HTML snippets capped at 120 chars; no pretty-print. Set false for the previous verbose shape.

Workflow: The response includes a scanId. Pass it to generate_fix_plan instead of pasting the full scan object — this avoids MCP client serialization issues and keeps chats smaller.

generate_fix_plan

Converts scan output into a structured AccessibilityFixPlan and writes .navable-plan.json when writeToDisk is true.

Input

Description

scanId

From run_accessibility_scan (preferred)

scan

Full scan JSON (fallback if the server was restarted; only the last 10 scans are cached)

writeToDisk

Write .navable-plan.json (default: true)

compact

true (default) when writing to disk: response is only planPath, summary, top 5 topItems, and manualReviewCount. Read the plan file for full item details. Set false to return the full plan in the tool response. Ignored when combined with writeToDisk: false (full plan is always returned).

Returns planPath (absolute) when the file is written successfully. On write failure, returns an error with the attempted path; set NAVABLE_PROJECT_ROOT in the MCP server env if needed.

update_fix_status

Mark fix plan items as done, skipped, or in progress. Prefer this over hand-editing .navable-plan.json.

Input

Description

fixId

Item ID(s), e.g. "fix-1" or ["fix-1", "fix-2"]

status

done, skipped, in_progress, or pending

planPath

Absolute path to plan file (optional; defaults to project root)

Returns updated progress summary (total, done, pending, skipped).

Available Resources

Resources use text/markdown. Prefer parameterized URIs during fix workflows to save context.

WCAG / compliance

URI

Size (typical)

Description

navable://docs/wcag-mapping

Compact

WCAG SC → EN 301 549 → testability → axe rules; summary stats; WCAG 2.2 forward-looking table

navable://docs/bfsg-legal

Large

BFSG legal context: scope, German glossary, enforcement, BITV 2.0, dates (optional)

Fix patterns (axe rule → before/after code)

URI

Size (typical)

Description

navable://docs/fix-patterns/{ruleIds}

Small

Preferred. Comma-separated axe rule IDs, no spaces. Example: navable://docs/fix-patterns/label,color-contrast,image-alt. Unknown IDs are skipped.

navable://docs/fix-patterns

Large (~49 KB)

All 55 documented rules

ARIA (WAI-ARIA APG patterns)

URI

Size (typical)

Description

navable://docs/aria-patterns

Compact index

Table: slug, name, complexity, short description

navable://docs/aria-patterns/{patternSlug}

Per pattern

Full detail (e.g. dialog-modal, combobox). Invalid slug → lists available slugs.

Semantic HTML

URI

Size (typical)

Description

navable://docs/semantic-html

Compact index

Table: element, implicit role, short description

navable://docs/semantic-html/{element}

Per element

Full detail (e.g. nav, button, input-checkbox). Invalid tag → lists available elements.

Configuration

Create a .navable.json in your project root to customize behavior:

{
  "allowedHosts": ["localhost", "127.0.0.1", "[::1]"],
  "timeout": 15000,
  "waitUntil": "load",
  "axeTags": ["wcag2a", "wcag21a", "wcag2aa", "wcag21aa"],
  "axeDisableRules": [],
  "engines": ["axe"],
  "htmlcsIgnore": [],
  "wcagLevel": "AA"
}

Option

Default

Description

allowedHosts

["localhost", "127.0.0.1", "[::1]"]

Hostnames the scanner may reach

timeout

15000

Navigation timeout in ms

waitUntil

"load"

Playwright wait strategy (load, domcontentloaded, networkidle, commit)

axeTags

["wcag2a", "wcag21a", "wcag2aa", "wcag21aa"]

axe-core tags to include

axeDisableRules

[]

axe-core rule IDs to skip

engines

["axe"]

Engines to run. Add "htmlcs" to also run Pa11y/HTMLCS as a second engine

htmlcsIgnore

[]

HTMLCS codes to suppress (see Pa11y / HTMLCS noise reduction below)

wcagLevel

"AA"

Target WCAG conformance level

Pa11y / HTMLCS as a second engine

Pa11y does not run by default. A plain run_accessibility_scan({ url }) call — and the default agent workflow — uses axe-core only. Pa11y/HTMLCS runs only when you opt in via the engines parameter or .navable.json.

When to use both engines

Use case

Recommended

Iterative fix loops (scan → fix → re-scan)

["axe"] (default) — fast, low token cost

One-shot compliance audit / BFSG / EN 301 549 sign-off

["axe", "htmlcs"] — cross-confirms findings

User explicitly asks for thorough / dual-engine scan

["axe", "htmlcs"]

How to enable Pa11y

Per scan — pass engines to the tool:

run_accessibility_scan({ url: "http://localhost:3000", engines: ["axe", "htmlcs"] })

Always on — add to .navable.json in your project root:

{
  "engines": ["axe", "htmlcs"]
}

How results change with both engines

When engines includes "htmlcs", Pa11y runs in parallel with axe-core and shares Playwright's Chromium binary (no extra download). Crossover findings are deduped server-side with a deliberate bias toward false negatives over false positives — ambiguous matches are kept as separate entries rather than collapsed. The dedup uses a confidence ladder, all gated on same WCAG SC:

  1. Full selector match (after normalizing html > body > prefixes and whitespace) + loose HTML compare (200-char prefix, whitespace-collapsed, lowercased).

  2. Strict suffix match — one selector is the tail of the other, with > immediately before the boundary (e.g. axe section:nth-child(3) > p matches HTMLCS #root > main > section:nth-child(3) > p) + loose HTML compare.

  3. Attribute-stripped suffix match (axe button[type="button"] vs HTMLCS button) + strict (full-string) HTML equality. Distinct elements like input[type="checkbox"] and input[type="radio"] collapse to the same stripped selector, so HTML must match exactly.

  4. Last-3-segment fingerprint match + positional discriminator (:nth-, #id, .class, or […] somewhere in the fingerprint) + loose HTML compare. The discriminator gate prevents false merges in repeating layouts (ul > li > a lists, grids).

Survivors:

  • Crossover-confirmed: kept as the axe entry, tagged with alsoFlaggedBy: ["htmlcs"].

  • HTMLCS-only: kept with source: "htmlcs", plus helpUrl (WCAG Understanding doc) and a one-sentence developerNote to give agents enough context to act on the cryptic HTMLCS codes.

Same-element overlaps under different WCAG criteria are kept separate. axe and HTMLCS often map the same element to different success criteria (e.g. a <select> with no label may surface as SC 3.3.2 and SC 4.1.2 and SC 1.3.1). Each is a real audit finding and dedup never collapses across SCs — that would lose traceability for compliance reporting. The scan-accessibility and fix-accessibility skills include guidance to group plan items by DOM element so the agent applies one HTML edit per element, then marks all related fix IDs resolved at once. Without this grouping, an agent may edit the same element repeatedly and risk one fix undoing another.

HTMLCS often emits advisory "Check that…" warnings intended for human auditors. They aren't useful for an AI agent and inflate token cost. Suppress them via htmlcsIgnore. Common candidates:

{
  "engines": ["axe", "htmlcs"],
  "htmlcsIgnore": [
    "WCAG2AA.Principle1.Guideline1_3.1_3_1.H49.AlignAttr",
    "WCAG2AA.Principle2.Guideline2_4.2_4_1.H64.1",
    "WCAG2AA.Principle1.Guideline1_3.1_3_1.H42.2"
  ]
}

Find more codes to suppress in your scan output — any HTMLCS id whose help text starts with “Check that…” is a likely candidate.

Set NAVABLE_PROJECT_ROOT in the MCP server environment (see Cursor example above) so .navable-plan.json resolves to your app’s repo root when the server’s cwd is not the project.

For a deterministic, repeatable workflow, pair this MCP server with @navable/skills — pre-built agent skills that guide your AI agent through scanning, fixing, reviewing, and auditing accessibility issues step by step.

The skills ensure your agent follows a consistent process (scan → plan → fix → verify) instead of improvising. Copy them into your project's skills folder:

# VS Code (Copilot)
cp -r skills/* .github/skills/

# Cursor
cp -r skills/* .agents/skills/

# Claude Code
cp -r skills/* .claude/skills/

See the skills repository for details.

Requirements

  • Node.js >= 20

  • Playwright Chromium — downloaded automatically on first scan. If auto-install fails, run npx playwright install chromium manually.

Contributing / development

We love getting feedback and contributions. Found a bug? Have an idea for a new fix pattern or ARIA guide? Open an issue or send a PR — we'll review it quickly.

git clone https://github.com/web-DnA/navable-web-accessibility-mcp.git
cd navable-web-accessibility-mcp
npm install
npx playwright install chromium
npm run dev   # watch mode

License

MIT — navable.io

Available Tools

3 tools
generate_fix_planAccessibility Fix Plan GeneratorA

Convert a scan result into a structured AccessibilityFixPlan and write it to .navable-plan.json.

PREFERRED WORKFLOW:

  1. Call run_accessibility_scan — it returns a "scanId" field in the result.

  2. Call generate_fix_plan with { scanId: "<value from step 1>" }. The scanId lookup is server-side — no need to pass the full scan JSON back.

FALLBACK WORKFLOW: Pass the full scan JSON as { scan: }. Use only when the scanId is no longer available (server was restarted; last 10 scans are kept).

WRITE LOCATION: Writes .navable-plan.json to the project root (auto-detected via package.json / .git walk-up). If the file ends up in the wrong place, set the NAVABLE_PROJECT_ROOT environment variable in your MCP server config to the absolute path of your project directory.

RESPONSE: Always includes "planPath" — the absolute path where the file was written. On write failure, returns an error with the attempted path and instructions to set NAVABLE_PROJECT_ROOT.

ParametersJSON Schema
NameRequiredDescriptionDefault
scanNoFallback: full JSON output from run_accessibility_scan. Use only when scanId is unavailable (e.g. server was restarted).
scanIdNoPreferred: the "scanId" value from run_accessibility_scan output. Avoids passing the full scan object through MCP parameters.
compactNoReturn compact summary (default: true). When true and writeToDisk is true, returns only planPath + summary + top 5 items. Set to false for the full plan in the response.
writeToDiskNoWrite .navable-plan.json to project root (default: true). Set NAVABLE_PROJECT_ROOT env var in MCP config to control the write location.

TDQS

A4.6/5.0
Behavior4/5

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

Annotations (readOnlyHint=false, destructiveHint=false) are minimal. The description compensates by disclosing write-to-disk behavior, fallback mechanism, and potential write failure. It does not explicitly state whether the file is overwritten, but the response always includes planPath.

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

Conciseness4/5

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

Description is well-structured with clear sections (preferred workflow, fallback, write location, response). While slightly verbose, each sentence serves a purpose. Front-loaded with core function.

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?

Given no output schema, the description explains the response includes planPath. It covers all usage scenarios, write location pitfalls, and parameter behaviors. Complete for a tool with 4 parameters and nested objects.

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?

Schema coverage is 100%, but the description adds significant context: scanId vs scan as preferred/fallback, default values for compact and writeToDisk, and limitations (server keeps last 10 scans). This aids the agent in parameter selection 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 converts a scan result into a structured AccessibilityFixPlan and writes to a file. It distinguishes from siblings by referencing run_accessibility_scan as a prerequisite and update_fix_status as a separate tool.

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

Usage Guidelines5/5

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

Explicitly provides preferred workflow (step 1: run_accessibility_scan, step 2: generate_fix_plan with scanId) and fallback workflow (pass full scan JSON). Also details write location and environment variable configuration, guiding the agent on when to use which approach.

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

run_accessibility_scanWCAG Accessibility ScannerA
Read-only

Scan a URL for WCAG 2.1 Level A + AA accessibility violations using Playwright + axe-core, with optional Pa11y (HTMLCS) as a second engine.

Returns structured violations grouped by severity with WCAG criteria and fix hints. Requires the target URL to be running and reachable.

ENGINES: Default: ["axe"]. Pass {"engines": ["axe", "htmlcs"]} to also run Pa11y/HTMLCS. Crossover findings are deduped server-side: an axe violation also flagged by HTMLCS is marked with alsoFlaggedBy: ["htmlcs"]. Adding HTMLCS typically grows the result by ~10-20% (mostly standalone HTMLCS findings) and adds ~2-4s wall-clock per scan.

NEXT STEP: The result includes a "scanId" field. Pass it directly to generate_fix_plan: generate_fix_plan({ scanId: "" }) Do NOT pass the full scan result object - use the scanId instead.

ParametersJSON Schema
NameRequiredDescriptionDefault
urlYesFull URL to scan (e.g. http://localhost:3000/checkout)
tagsNoaxe-core rule tags to include (default: wcag2a, wcag21a, wcag2aa, wcag21aa)
compactNoReturn compact format (default: true). Set to false for the full verbose format with description, helpUrl, wcag tags, failureSummary, and full wcagCriteria fields.
enginesNoEngines to run (default: ["axe"]). Add "htmlcs" to also run Pa11y/HTMLCS for crossover validation. Configurable via .navable.json "engines".
excludeNoCSS selectors to exclude from scan
includeNoCSS selectors to limit scan scope

TDQS

A4.4/5.0
Behavior4/5

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

Beyond the readOnlyHint and destructiveHint annotations, the description adds that the URL must be reachable, explains engine behavior with deduping, and notes performance cost (~2-4s with HTMLCS). No contradictions.

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 well-structured with sections for engines and next step, concise yet informative, and front-loaded with the main purpose. 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?

Given the complexity (6 params, no output schema), the description covers key aspects: engines behavior, performance, and next step. It could detail output structure more, but the mention of grouped violations and scanId is sufficient.

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?

With 100% schema coverage, baseline is 3. The description adds meaning for engines (deduping, default), tags, and compact format details, exceeding the schema's basic descriptions.

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 scans a URL for WCAG 2.1 Level A+AA violations using Playwright and axe-core with optional Pa11y. It distinguishes from siblings by mentioning the next step of using generate_fix_plan with the scanId.

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 provides context for when to use the tool (scanning a URL) and directs the next step to generate_fix_plan. It does not explicitly state when not to use it or compare with alternatives, but the sibling distinction is clear.

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

update_fix_statusFix Status UpdaterA

Update the status of one or more items in .navable-plan.json.

Use after applying a fix to mark it as done, or to skip an item. Reads the plan from the project root (or planPath), updates the matching items, and writes the file back. Returns the updated summary.

ParametersJSON Schema
NameRequiredDescriptionDefault
fixIdYesFix item ID(s) to update, e.g. "fix-1" or ["fix-1", "fix-2"]
statusYesNew status for the item(s)
planPathNoAbsolute path to .navable-plan.json. If omitted, resolves from project root.

TDQS

A4.2/5.0
Behavior4/5

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

Annotations indicate write (readOnlyHint=false) and non-destructive (destructiveHint=false). Description adds process details: reads, updates, writes, returns summary. No contradiction.

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?

Three concise sentences: purpose, usage, process. Front-loaded with action and resource. No fluff.

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?

Describes purpose, when to use, process (read, update, write), and return (summary). No output schema, but summary is implied. Covers all relevant aspects for a simple tool.

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 has 100% description coverage for all 3 parameters. Description adds context about planPath resolving from project root, but does not add new parameter meaning beyond the schema. Baseline 3.

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?

Clear verb ('Update'), specific resource ('items in .navable-plan.json'), and scope ('one or more'). Distinguishes from siblings 'generate_fix_plan' and 'run_accessibility_scan' which are different actions.

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?

Explicitly states when to use: 'Use after applying a fix to mark it as done, or to skip an item.' Implies not for generating plans or scanning. Mentions reading/writing file, but no explicit alternatives or exclusions.

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

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 3 tool updatesv0.3.0
    • First observedgenerate_fix_plan
    • First observedrun_accessibility_scan
    • First observedupdate_fix_status

TDQS

A4.4/5.0

Scored across 3 tools

Disambiguation5/5

Each tool serves a distinct function: scanning, generating a fix plan, and updating status. No overlap.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern with snake_case (run_accessibility_scan, generate_fix_plan, update_fix_status) and clear verbs.

Tool Count5/5

Three tools is well-scoped for a specialized accessibility scanning and fix-planning domain, covering the essential actions without bloat.

Completeness4/5

Covers the core workflow: scan, generate plan, update status. Minor gaps like viewing the plan metadata or listing scans, but the set is complete for the primary use case.

Maintenance

ActivityStale
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers