{
  "markdown": "# a11y-toolkit — the accessibility layer for AI coding agents\n\n[![CI](https://github.com/kinti/a11y-toolkit/actions/workflows/ci.yml/badge.svg)](https://github.com/kinti/a11y-toolkit/actions/workflows/ci.yml)\n[![PyPI](https://img.shields.io/pypi/v/a11y-toolkit)](https://pypi.org/project/a11y-toolkit/)\n[![Downloads](https://img.shields.io/pypi/dm/a11y-toolkit)](https://pypistats.org/packages/a11y-toolkit)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n[![Python 3.9+](https://img.shields.io/badge/python-3.9%2B-blue.svg)](pyproject.toml)\n[![MCP](https://img.shields.io/badge/Model%20Context%20Protocol-server-purple)](https://modelcontextprotocol.io)\n\n**16 MCP tools + 5 prompts + a skill** that give any AI agent (Claude, Cursor, Windsurf,\nCodex…) the full WCAG 2.2 loop: **audit → fix → document → watch**. Zero dependencies at\nits core; every finding ships with a concrete remediation your agent can apply.\n\nAccessibility is not optional anymore: the **European Accessibility Act is in force since\nJune 2025**, ADA suits keep landing, and AI agents now write most of the web. This toolkit\nmakes \"is it accessible?\" a one-question ask — and \"then fix it\" a one-command job.\n\n<p align=\"center\">\n  <img src=\"docs/demo.gif\" alt=\"a11y-toolkit in action: audit a page (score 64), get the nearest passing color (#767676), re-audit (94) — real tool output\" width=\"720\">\n</p>\n\n## What no other a11y tool gives an agent\n\n| Capability | axe-core / Lighthouse / pa11y | a11y-toolkit |\n|---|---|---|\n| Text contrast over **images/gradients** (pixel sampling of the real background, hostile-zone grid) | ✗ | ✓ |\n| Legal **accessibility statements** (EAA / RD 1112/2018), accessible HTML, es/en | ✗ | ✓ |\n| **Regression watch** between builds: accessible names + real tab-order diff | ✗ | ✓ |\n| **Remediation text per finding**, written for an agent to apply | ✗ | ✓ |\n| **Focus-order regression detection** | ✗ | ✓ |\n| Runs with **zero dependencies** (stdlib only; Playwright optional for the deep pass) | heavy runtimes | ✓ |\n| Screen-reader **aria-live announcement monitor** | ✗ | ✓ |\n| **0-100 score** computed from weighted findings | ✓ (Lighthouse, subset of rules) | ✓ (fuller rule set) |\n| **Criterion explanations** on demand for agents | ✗ | ✓ |\n| Static core parity: ARIA validity, autocomplete 1.3.5, link purpose, list structure, duplicate ids | ✓ | ✓ |\n| Output optimized for **MCP/LLM consumption** (JSON, severity-ranked, es/en) | ✗ | ✓ |\n\n## The tools (16)\n\n| Tool | What it does |\n|---|---|\n| `a11y_audit_url` | Express static WCAG audit of a URL **or raw HTML**: 20+ signals with a **weighted 0-100 score** (alt, accessible names, labels, autocomplete 1.3.5, keyboard onclick, unknown ARIA roles, broken aria-labelledby, unnamed duplicated landmarks, meta refresh, skip mechanism, lang validity, title, headings, blocked zoom, captions, autoplay audio, generic/duplicated link text, target=_blank warnings, tabindex>0, aria-hidden-on-focusable, tables, duplicate ids, accesskeys). Per-finding remediation. |\n| `a11y_audit_dom` | **Rendered audit** (local Playwright/Chromium): real computed text contrast vs effective backgrounds with alpha compositing (1.4.3), minimum target size 24×24 (**2.5.8 — new in WCAG 2.2**), focus-indicator heuristic (2.4.7), **:focus/:hover state contrast**, **open shadow DOM traversed** — all static checks on the live DOM. |\n| `a11y_contrast_pair` | Exact ratio + verdicts 1.4.3/1.4.6/1.4.11. Accepts `#hex`, `rgb()`, `hsl()`, **CSS color names**; alpha composites over the background. Suggests the nearest passing color. |\n| `a11y_contrast_image` | **Text over images**: pixel-level sampling of the actual background → worst/median/p95 ratio, % area passing AA, hostile-zone detection on a 3×3 grid. |\n| *(rendered audit)* | adds **:focus/:hover state contrast** (disabled exempt) and **same-origin iframes** |\n| `a11y_suggest_color` | Nearest opaque color (true RGB distance) reaching the target ratio (4.5 default). |\n| `a11y_generate_declaration` | Legal accessibility statement in HTML: RD 1112/2018 art. 10 (Spanish public sector) or **European Accessibility Act** wording (Directive (EU) 2019/882 / Ley 11/2023). es/en. The document is itself accessible. |\n| `a11y_snapshot` | Interactive elements (tag, role, accessible name, href) + **real tab focus order** + the **computed accessibility tree** (what a screen reader announces). Requires Playwright. |\n| `a11y_diff` | Regression diff between two snapshots: added/removed/renamed interactives, focus-order changes. |\n| `a11y_diff_urls` | Snapshot two URLs and diff in one call (staging vs production). |\n| `a11y_aria_live_snippet` | Injectable monitor logging every aria-live announcement (time, politeness, role, text) — what a screen reader would say, visible on screen. |\n| `a11y_criterion` | Explains any WCAG 2.2 criterion in plain language: what it requires, typical failures, and which toolkit tool verifies it. |\n| `a11y_scroll` | **Infinite-scroll audit** — the documented disaster nobody automates (Deque + APG Feed pattern): real scrolling batches, does focus SURVIVE, is new content ANNOUNCED, does the feed END or offer load-more. |\n| `a11y_keyboard` | **Keyboard-trap detection (2.1.2) with REAL Tab walking**: up to 60 stops, cycle detection, and the decisive test — does Escape release? Correct modals are not reported. |\n| `a11y_autofix` | **Deterministic safe auto-fixes** on HTML: unblock zoom (1.4.4), exact autocomplete tokens (1.3.5), missing lang, empty title. Everything requiring judgment is returned as `no_aplicados` with the reason — the honest anti-overlay. |\n| `a11y_reflow` | **Reflow at 320px (1.4.10)** — the check axe and Lighthouse don't automate: real horizontal scroll + overflowing elements at 320px viewport. |\n| `a11y_badge` | Returns an **honest badge** as accessible SVG: score, date, scope (\"automated screening\"), never \"conformant\" — the anti-overclaim seal. |\n\n**5 prompts** (slash-commands in supporting clients): `audit-page` (full audit workflow +\nwhat automation can't check), `fix-contrast`, `pre-deploy-check` (audit + diff → GO/NO-GO),\n`declaration-eaa` (collects legal fields, generates), `conformance-wcagem` (the three-tier\nWCAG-EM ladder).\n\n## Install\n\n> Registry name: `mcp-name: io.github.kinti/a11y-toolkit` · PyPI: [a11y-toolkit](https://pypi.org/project/a11y-toolkit/)\n\n**Claude Code** (one command):\n\n```bash\nclaude mcp add a11y-toolkit -- uvx --from a11y-toolkit a11y-toolkit-mcp\n```\n\n**Any MCP client with JSON config** (Claude Desktop, Cursor, Windsurf, VS Code…):\n\n```json\n{\n  \"mcpServers\": {\n    \"a11y-toolkit\": {\n      \"command\": \"uvx\",\n      \"args\": [\"--from\", \"a11y-toolkit\", \"a11y-toolkit-mcp\"],\n      \"timeoutMs\": 60000\n    }\n  }\n}\n```\n\nOr from the repo without publishing:\n\n```json\n{ \"mcpServers\": { \"a11y-toolkit\": {\n    \"command\": \"uvx\", \"args\": [\"--from\", \"git+https://github.com/kinti/a11y-toolkit\", \"a11y-toolkit-mcp\"] } } }\n```\n\nThe rendered audit, snapshots and diffs use Playwright **if present**\n(`pip install playwright && playwright install chromium`); everything else works with\nzero dependencies.\n\n### The skill (teaches your agent when/how to use all of this)\n\n```bash\ngit clone https://github.com/kinti/a11y-toolkit && cd a11y-toolkit\n./skill/install-skill.sh     # → ~/.zcode/skills and ~/.claude/skills\n```\n\n## CLI — same engine, one command\n\n```bash\na11ytoolkit pair \"#1f2328\" \"#fbfaf7\"                     # contrast, per-criterion verdicts\na11ytoolkit image hero.jpg --text \"#ffffff\" --region 120,40,420,90\na11ytoolkit audit --url https://example.com --lang en    # express static audit\na11ytoolkit declaration --entidad \"Acme\" --url https://acme.example \\\n       --estado parcial --marco eaa --lang en --output decl.html\na11ytoolkit snapshot https://mysite --out before.json    # before deploy (needs Playwright)\na11ytoolkit diff before.json after.json                  # after deploy\n```\n\nRun from a clone with `python3 a11y.py <subcommand>`; from PyPI with `uvx --from\na11y-toolkit a11ytoolkit …`.\n\n### Watch it continuously (the deployment gate)\n\n```bash\na11ytoolkit audit --url https://mysite --pages 5 > audit.json        # light crawl\npython3 -m a11ybudget --init < audit.json > budget.json       # accept today's baseline\na11ytoolkit budget --budget budget.json --audit audit.json           # only NEW findings block (exit 2)\na11ytoolkit sarif --from-audit audit.json -o a11y.sarif              # GitHub code scanning format\n```\n\n`examples/a11y-watch.yml` turns this into a weekly scheduled check that fails\non regressions and publishes the SARIF to code scanning.\n\n## Validated against real pages, not just fixtures\n\nBefore shipping the current rule set we benchmarked against axe-core 4.10 on real\npages ([methodology and results](bench/README.md)) — same Chromium, same Playwright.\nThat pass **caught a real WCAG failure on gov.uk that axe does not report** (blue\nbutton text at 3.91:1, manually verified) and drove out five of our own false\npositives (hidden skip links reported as tiny targets, honeypot fields, non-tabbable\n`aria-hidden` controls, single-context generic links). Every divergence has a\nregression fixture.\n\n## Honesty, built in\n\nAutomation covers **~1/3 of WCAG** — every audit says so. The `audit-page` prompt and the\nbundled skill then have the agent check what it *can* (keyboard operability, focus\nvisibility, zoom reflow, announced errors) using\n[the manual checklist](skill/a11y-toolkit/references/wcag22-manual-checklist.md), and\nrecommend a screen-reader pass for the rest. A filter, not a verdict.\n\n## Security & scope\n\nA **local** tool: runs on your machine as your user. `path` (image) and `output_path`\n(statement) read/write local paths — use it in MCP clients you trust. Nothing leaves your\nmachine except the URL you explicitly audit.\n\n## Development\n\n```bash\npython3 test_contrast.py && python3 test_audit.py && python3 test_dom.py && python3 test_mcp.py\n```\n\n`test_dom.py` self-skips without Playwright. Releases: tag `vX.Y.Z` → CI publishes to PyPI\n(trusted publishing); `server.json` is the official MCP Registry manifest. Listed on\n[Smithery](https://smithery.ai) too. Contributions welcome — see\n[CONTRIBUTING.md](CONTRIBUTING.md) (the golden rules: zero dependencies at the core,\nes/en strings everywhere, honest scope notes).\n\n## Roadmap\n\n- [x] Rendered audit (computed contrast, target size 2.5.8, focus indicator)\n- [x] 0-100 weighted score · ARIA validity · criterion explanations\n- [x] Computed accessibility tree in snapshots + tree diff\n- [x] SARIF export → findings as GitHub code-scanning / PR annotations (`a11ytoolkit sarif`)\n- [x] Honest dated badge as accessible SVG (`a11y_badge`)\n- [x] Accessibility error budget: only NEW findings block (`a11ytoolkit budget` + `examples/a11y-watch.yml`)\n- [x] Multi-page same-domain crawl with aggregated scores (`pages` parameter)\n- [x] Scheduled surveillance recipe (weekly audit + budget gate as a GitHub Action)\n- [x] WCAG-EM conformance ladder (`conformance-wcagem` prompt + guided protocol)\n- [x] Same-origin iframes in the rendered audit + :focus/:hover state contrast\n\n---\n\n## Author\n\n**Jesús Quintana Fernández** ([jquin.net](https://jquin.net/)) — SEO/GEO consultant and\nweb-accessibility practitioner since 2003. MIT © 2026.\n",
  "bytes": 11267,
  "sha": "c1ef97d0413e9737d6639524b2d24e09730ea834c322437b2c8572c80ad7d50c",
  "repo_slug": "kinti/a11y-toolkit",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_kinti_a11y_toolkit_8747d64b/readme"
}