Skip to main content
Glama
ksmuvva

Accessibility MCP

by ksmuvva
README.md
# Accessibility MCP — WCAG 2.2 AA (GOV.UK standard)

A [Model Context Protocol](https://modelcontextprotocol.io) server that audits web
pages and sites for **WCAG 2.2 level AA** accessibility, aligned with the
[GOV.UK / GDS standard](https://www.gov.uk/guidance/accessibility-requirements-for-public-sector-websites-and-apps)
that UK public sector bodies are legally required to meet (since 1 October 2024).

It drives a real headless Chromium (via Playwright) and runs up to **four
independent accessibility engines** — [axe-core](https://github.com/dequelabs/axe-core),
[pa11y](https://github.com/pa11y/pa11y) (HTML_CodeSniffer + axe),
[Lighthouse](https://github.com/GoogleChrome/lighthouse) and
[IBM Equal Access](https://github.com/IBMa/equal-access) — layers **GOV.UK-specific
checks** and remediation guidance on top, and returns results as structured JSON,
a human-readable Markdown report, and a **GDS-style compliance summary**.

It can drive **interactive journeys** (navigate, click, fill, log in) and audit the
resulting state. **Optimized for efficiency with 41 streamlined tools** instead of 168 individual rule tools.

> **Honest by design.** Automated testing detects only ~30–40% of WCAG issues.
> Every report separates *automated failures*, *needs manual review*, and *passed*
> checks, and any unverified AA criterion keeps the status at "partially compliant".
> This tool is a starting point for, not a replacement for, a full manual audit.

## Tools

**Bundled audits (multi-engine):**

| Tool | Description |
| --- | --- |
| `audit_url` | Audit one live page; supports `engines` and interaction `steps`. |
| `audit_html` | Audit a raw HTML string / component snippet (no network fetch). |
| `audit_site` | Crawl a site (same origin) and audit each page; aggregated summary. |

**Dedicated single-engine audits** (take `url`, `html` or `session_id`):

| Tool | Description |
| --- | --- |
| `audit_axe` | axe-core only (plus GOV.UK checks). |
| `audit_pa11y` | pa11y only (HTML_CodeSniffer + axe runners). |
| `audit_lighthouse` | Lighthouse accessibility only. |
| `audit_ibm` | IBM Equal Access only. |

**Interactive navigation (stateful browser session):**

| Tool | Description |
| --- | --- |
| `browser_open` | Open a session; returns a `session_id`. |
| `browser_navigate` / `browser_click` / `browser_fill` / `browser_wait` | Drive the page. |
| `browser_snapshot` | Current url, title and visible text. |
| `audit_current_page` | Audit the current post-interaction state. |
| `browser_close` | Close the session. |

**Automated checks & rule-specific audits:**

| Tool | Description |
| --- | --- |
| `audit_automated_checks` | Runs every automatable WCAG criterion at once. |
| `axe_check_rule` | Check any axe-core rule by ID (replaces 100+ individual tools). |
| `list_automated_checks` | WCAG criteria that can be automated. |
| `list_manual_checks` | WCAG criteria requiring human review. |

**Grouped audit tools:** run related rules at once.

| Tool | Description |
| --- | --- |
| `audit_perceivable` / `audit_operable` / `audit_understandable` / `audit_robust` | All axe rules under a WCAG principle. |
| `audit_group_color`, `audit_group_forms`, `audit_group_keyboard`, `audit_group_aria`, etc. | All axe rules in a category (12 total). |
| `list_groups` | Lists every group tool and the rules it runs. |

**Catalogue / reporting:**

| Tool | Description |
| --- | --- |
| `list_engines` | Available engines and Node runner installation status. |
| `list_wcag_rules` | WCAG 2.2 criteria checked, with automation coverage. |
| `list_axe_rules` | All 105 axe rules available for `axe_check_rule`. |
| `generate_accessibility_statement` | Draft a GOV.UK-format statement from an audit. |

Each audit tool returns:
- `json` — structured, machine-readable results (violations, severity, WCAG
  criteria, affected selectors, remediation);
- `markdown_report` — a human-readable report grouped by severity;
- `gds_summary` — a GOV.UK-flavoured *compliant / partially compliant / not
  compliant* summary with reasons;
- `audit_id` — pass it to `generate_accessibility_statement` to reuse the result.

## Recent Optimizations

**🎯 Ponytail Performance Improvements (v0.2):**
- **Tool count:** 168 → 41 tools (-76% reduction)
- **Interface:** Replaced 100+ per-rule tools with single `axe_check_rule(rule_id)` 
- **Performance:** Simplified configuration, faster server startup
- **Functionality:** All accessibility testing engines preserved
- **Code quality:** Removed 200+ lines of unnecessary complexity

## Engines

Choose engines per call via `engines=["axe","pa11y","lighthouse","ibm"]` (default
`["axe"]`). Findings from every engine are normalised to a common shape with WCAG
criteria and labelled by `source`, so you can cross-check results.

| Engine | Language | Notes |
| --- | --- | --- |
| `axe` | Python (in-process) | Deque axe-core, explicit WCAG 2.2 tags. Always available. |
| `pa11y` | Node | HTML_CodeSniffer + axe runners. Replays `steps` as pa11y actions. |
| `lighthouse` | Node | Google Lighthouse accessibility category. Audits by URL. |
| `ibm` | Node | IBM Equal Access. **Needs network egress to its rule archive** (`cdn.jsdelivr.net`); in locked-down networks it returns a structured engine-error instead of crashing the run. |

axe runs in-process; the other three run in a Node subprocess
(`accessibility_mcp/engines_node/`). If the Node runner is not installed, those
engines report a clear "not installed" error and axe still works.

## What it checks

- **Full axe-core WCAG 2.2 rule set** — 105 rules covering contrast, alt text, labels, names, landmarks, etc.
- **pa11y / Lighthouse / IBM** — independent rulesets for cross-checking.
- **GOV.UK custom checks** — accessibility-statement link presence, "Skip to main content" skip link, a single `<main>` landmark, and GOV.UK Design System usage.
- **WCAG 2.2 awareness** — flags the criteria new in 2.2 (2.4.11, 2.5.7, 2.5.8, 3.2.6, 3.3.7, 3.3.8) and marks non-automatable criteria as *needs manual review* rather than silently passing them.

## Installation

```bash
python -m venv .venv && source .venv/bin/activate
pip install -e .
# Chromium: this server reuses an existing Playwright Chromium if present
# (see configuration), otherwise install one:
playwright install chromium

# Optional — pa11y, Lighthouse and IBM engines (needs Node.js):
bash accessibility_mcp/engines_node/setup.sh
```

axe-core is vendored in `accessibility_mcp/vendor/axe.min.js` — no CDN needed. The
axe rule catalogue (`vendor/axe-rules.json`) contains 105 rules for `axe_check_rule`.

The Node engines reuse the same Chromium as axe (no extra browser download). Only
`axe` is required; the others are optional and degrade gracefully if absent.

## Running

```bash
# Run directly over stdio:
accessibility-mcp
# or
python -m accessibility_mcp.server
```

### Register with an MCP client

Add to your client config (e.g. Claude Desktop `claude_desktop_config.json`, or
the example `mcp.json` in this repo):

```json
{
  "mcpServers": {
    "accessibility": {
      "command": "accessibility-mcp"
    }
  }
}
```

If you installed into a virtualenv, point `command` at that venv's executable, e.g.
`/path/to/.venv/bin/accessibility-mcp`.

## Configuration (environment variables)

| Variable | Default | Purpose |
| --- | --- | --- |
| `ACCESSIBILITY_MCP_CHROMIUM` | auto-detect | Explicit Chromium executable path. |
| `PLAYWRIGHT_BROWSERS_PATH` | (Playwright default) | Searched for an installed Chromium build. |

> **Chromium auto-detection.** MCP clients spawn the server with a *sanitised*
> environment (typically just `HOME`/`PATH`/`SHELL`/`TERM`), so
> `PLAYWRIGHT_BROWSERS_PATH` is usually stripped before the server starts. When it
> is absent, the server still probes well-known default install locations
> (`/opt/pw-browsers`, `~/.cache/ms-playwright`) so audits work out of the box. Set
> `ACCESSIBILITY_MCP_CHROMIUM` to override discovery explicitly.
| `ACCESSIBILITY_MCP_PROXY` / `HTTPS_PROXY` | none | Outbound proxy for `audit_url` / `audit_site`. |
| `ACCESSIBILITY_MCP_PAGE_TIMEOUT_MS` | `30000` | Page load timeout. |
| `ACCESSIBILITY_MCP_MAX_PAGES` | `20` | Default crawl page limit. |
| `ACCESSIBILITY_MCP_MAX_DEPTH` | `2` | Default crawl depth limit. |

`audit_url` / `audit_site` need outbound network access to the target site. In
locked-down environments behind an egress policy, set `HTTPS_PROXY` (Chromium is
pointed at it automatically); `audit_html` needs no network.

## Development

```bash
pip install -e ".[dev]"
pytest                 # unit + browser-backed integration tests (local fixtures)
```

The integration tests drive a real headless Chromium against the HTML fixtures in
`tests/fixtures/`, so they require a working Chromium but no network access.

## Architecture

```
accessibility_mcp/
  server.py            FastMCP entry point — 41 optimized tools
  audit.py             Orchestration (URL / HTML / site / single rule / open page)
  config.py            WCAG tags, engines, browser/proxy discovery, limits
  engine/              browser.py, axe_runner.py, crawler.py, node_bridge.py, session.py
  engines_node/        Node runner for pa11y / Lighthouse / IBM (runner.mjs, setup.sh)
  rules/               wcag22.py, govuk_checks.py, remediation.py, normalize.py, axe_rules.py
  reporting/           models.py, builder.py, json/markdown/gds renderers
  vendor/              axe.min.js, axe-rules.json (105 axe rules)
scripts/generate_axe_rules.py   Regenerate vendor/axe-rules.json from axe-core
```

## Disclaimer

This server helps identify accessibility problems and draft an accessibility
statement. It does not, on its own, establish legal compliance. A full manual
audit (keyboard operation, screen-reader testing, focus order, captions, etc.) is
required to claim conformance with WCAG 2.2 AA.

TDQS

B3.4/5.0

Scored across 41 tools

Disambiguation4/5

Tools are largely distinct with clear descriptions, but some overlap exists (e.g., audit_automated_checks vs audit_axe, or audit_url vs audit_current_page). The group and principle audits are well separated.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern with underscores (audit_*, browser_*, list_*, etc.). No mix of styles, highly predictable.

Tool Count3/5

41 tools is on the high side but justified by the breadth of accessibility auditing (multiple engines, groups, principles, site crawl, browser session). Could be streamlined but not excessive.

Completeness5/5

The tool surface covers automated checks, manual checks, multiple engines, site crawling, browser interactions, rule listing, and statement generation. No obvious gaps for the intended domain.

Maintenance

ActivityInactive
ResponsivenessNo issues