a11y-toolkit 3.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Jesús Quintana Fernández
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,188 @@
1
+ Metadata-Version: 2.4
2
+ Name: a11y-toolkit
3
+ Version: 3.3.0
4
+ Summary: The accessibility layer for AI coding agents — MCP server + CLI for WCAG 2.2: express static audit, rendered audit (contrast, 2.5.8 target size, focus), contrast math (pairs, CSS names, hsl/rgba, text-over-image pixel sampling), EAA/RD 1112/2018 declarations, snapshot regression diffs, aria-live monitor. Zero dependencies at core; es/en.
5
+ Author: Jesús Quintana Fernández
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/kinti/a11y-toolkit
8
+ Project-URL: Issues, https://github.com/kinti/a11y-toolkit/issues
9
+ Project-URL: Changelog, https://github.com/kinti/a11y-toolkit/blob/main/CHANGELOG.md
10
+ Keywords: mcp,accessibility,a11y,wcag,wcag22,contrast,audit,eaa,ada,screen-reader,playwright,ai-agents
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Topic :: Software Development :: Quality Assurance
14
+ Classifier: Topic :: Internet :: WWW/HTTP :: Browsers
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Operating System :: OS Independent
17
+ Requires-Python: >=3.9
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Dynamic: license-file
21
+
22
+ # a11y-toolkit — the accessibility layer for AI coding agents
23
+
24
+ [![CI](https://github.com/kinti/a11y-toolkit/actions/workflows/ci.yml/badge.svg)](https://github.com/kinti/a11y-toolkit/actions/workflows/ci.yml)
25
+ [![PyPI](https://img.shields.io/pypi/v/a11y-toolkit)](https://pypi.org/project/a11y-toolkit/)
26
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
27
+ [![Python 3.9+](https://img.shields.io/badge/python-3.9%2B-blue.svg)](pyproject.toml)
28
+ [![MCP](https://img.shields.io/badge/Model%20Context%20Protocol-server-purple)](https://modelcontextprotocol.io)
29
+ [![Smithery](https://smithery.ai/badge)](https://smithery.ai)
30
+
31
+ **12 MCP tools + 5 prompts + a skill** that give any AI agent (Claude, Cursor, Windsurf,
32
+ Codex…) the full WCAG 2.2 loop: **audit → fix → document → watch**. Zero dependencies at
33
+ its core; every finding ships with a concrete remediation your agent can apply.
34
+
35
+ Accessibility is not optional anymore: the **European Accessibility Act is in force since
36
+ June 2025**, ADA suits keep landing, and AI agents now write most of the web. This toolkit
37
+ makes "is it accessible?" a one-question ask — and "then fix it" a one-command job.
38
+
39
+ ## What no other a11y tool gives an agent
40
+
41
+ | Capability | axe-core / Lighthouse / pa11y | a11y-toolkit |
42
+ |---|---|---|
43
+ | Text contrast over **images/gradients** (pixel sampling of the real background, hostile-zone grid) | ✗ | ✓ |
44
+ | Legal **accessibility statements** (EAA / RD 1112/2018), accessible HTML, es/en | ✗ | ✓ |
45
+ | **Regression watch** between builds: accessible names + real tab-order diff | ✗ | ✓ |
46
+ | **Remediation text per finding**, written for an agent to apply | ✗ | ✓ |
47
+ | **Focus-order regression detection** | ✗ | ✓ |
48
+ | Runs with **zero dependencies** (stdlib only; Playwright optional for the deep pass) | heavy runtimes | ✓ |
49
+ | Screen-reader **aria-live announcement monitor** | ✗ | ✓ |
50
+ | **0-100 score** computed from weighted findings | ✓ (Lighthouse, subset of rules) | ✓ (fuller rule set) |
51
+ | **Criterion explanations** on demand for agents | ✗ | ✓ |
52
+ | Static core parity: ARIA validity, autocomplete 1.3.5, link purpose, duplicate ids | ✓ | ✓ |
53
+ | Output optimized for **MCP/LLM consumption** (JSON, severity-ranked, es/en) | ✗ | ✓ |
54
+
55
+ ## The tools (10)
56
+
57
+ | Tool | What it does |
58
+ |---|---|
59
+ | `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. |
60
+ | `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), all static checks on the live DOM. |
61
+ | `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. |
62
+ | `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. |
63
+ | *(rendered audit)* | adds **:focus/:hover state contrast** (disabled exempt) and **same-origin iframes** |
64
+ | `a11y_suggest_color` | Nearest opaque color (true RGB distance) reaching the target ratio (4.5 default). |
65
+ | `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. |
66
+ | `a11y_snapshot` | Interactive elements (tag, role, accessible name, href) + **real tab focus order** + the **computed accessibility tree** (what a screen reader announces). Requires Playwright. |
67
+ | `a11y_diff` | Regression diff between two snapshots: added/removed/renamed interactives, focus-order changes. |
68
+ | `a11y_diff_urls` | Snapshot two URLs and diff in one call (staging vs production). |
69
+ | `a11y_aria_live_snippet` | Injectable monitor logging every aria-live announcement (time, politeness, role, text) — what a screen reader would say, visible on screen. |
70
+ | `a11y_criterion` | Explains any WCAG 2.2 criterion in plain language: what it requires, typical failures, and which toolkit tool verifies it. |
71
+ | `a11y_badge` | Returns an **honest badge** as accessible SVG: score, date, scope ("automated screening"), never "conformant" — the anti-overclaim seal. |
72
+
73
+ **Prompts** (slash-commands in supporting clients): `audit-page` (full audit workflow +
74
+ what automation can't check), `fix-contrast`, `pre-deploy-check` (audit + diff → GO/NO-GO),
75
+ `declaration-eaa` (collects legal fields, generates).
76
+
77
+ ## Install
78
+
79
+ **Claude Code** (one command):
80
+
81
+ ```bash
82
+ claude mcp add a11y-toolkit -- uvx --from a11y-toolkit a11y-toolkit-mcp
83
+ ```
84
+
85
+ **Any MCP client with JSON config** (Claude Desktop, Cursor, Windsurf, VS Code…):
86
+
87
+ ```json
88
+ {
89
+ "mcpServers": {
90
+ "a11y-toolkit": {
91
+ "command": "uvx",
92
+ "args": ["--from", "a11y-toolkit", "a11y-toolkit-mcp"],
93
+ "timeoutMs": 60000
94
+ }
95
+ }
96
+ }
97
+ ```
98
+
99
+ Or from the repo without publishing:
100
+
101
+ ```json
102
+ { "mcpServers": { "a11y-toolkit": {
103
+ "command": "uvx", "args": ["--from", "git+https://github.com/kinti/a11y-toolkit", "a11y-toolkit-mcp"] } } }
104
+ ```
105
+
106
+ The rendered audit, snapshots and diffs use Playwright **if present**
107
+ (`pip install playwright && playwright install chromium`); everything else works with
108
+ zero dependencies.
109
+
110
+ ### The skill (teaches your agent when/how to use all of this)
111
+
112
+ ```bash
113
+ git clone https://github.com/kinti/a11y-toolkit && cd a11y-toolkit
114
+ ./skill/install-skill.sh # → ~/.zcode/skills and ~/.claude/skills
115
+ ```
116
+
117
+ ## CLI — same engine, one command
118
+
119
+ ```bash
120
+ a11y pair "#1f2328" "#fbfaf7" # contrast, per-criterion verdicts
121
+ a11y image hero.jpg --text "#ffffff" --region 120,40,420,90
122
+ a11y audit --url https://example.com --lang en # express static audit
123
+ a11y declaration --entidad "Acme" --url https://acme.example \
124
+ --estado parcial --marco eaa --lang en --output decl.html
125
+ a11y snapshot https://mysite --out before.json # before deploy (needs Playwright)
126
+ a11y diff before.json after.json # after deploy
127
+ ```
128
+
129
+ Run from a clone with `python3 a11y.py <subcommand>`; from PyPI with `uvx --from
130
+ a11y-toolkit a11y …`.
131
+
132
+ ### Watch it continuously (the deployment gate)
133
+
134
+ ```bash
135
+ a11y audit --url https://mysite --pages 5 > audit.json # light crawl
136
+ python3 -m a11ybudget --init < audit.json > budget.json # accept today's baseline
137
+ a11y budget --budget budget.json --audit audit.json # only NEW findings block (exit 2)
138
+ a11y sarif --from-audit audit.json -o a11y.sarif # GitHub code scanning format
139
+ ```
140
+
141
+ `examples/a11y-watch.yml` turns this into a weekly scheduled check that fails
142
+ on regressions and publishes the SARIF to code scanning.
143
+
144
+ ## Honesty, built in
145
+
146
+ Automation covers **~1/3 of WCAG** — every audit says so. The `audit-page` prompt and the
147
+ bundled skill then have the agent check what it *can* (keyboard operability, focus
148
+ visibility, zoom reflow, announced errors) using
149
+ [the manual checklist](skill/a11y-toolkit/references/wcag22-manual-checklist.md), and
150
+ recommend a screen-reader pass for the rest. A filter, not a verdict.
151
+
152
+ ## Security & scope
153
+
154
+ A **local** tool: runs on your machine as your user. `path` (image) and `output_path`
155
+ (statement) read/write local paths — use it in MCP clients you trust. Nothing leaves your
156
+ machine except the URL you explicitly audit.
157
+
158
+ ## Development
159
+
160
+ ```bash
161
+ python3 test_contrast.py && python3 test_audit.py && python3 test_dom.py && python3 test_mcp.py
162
+ ```
163
+
164
+ `test_dom.py` self-skips without Playwright. Releases: tag `vX.Y.Z` → CI publishes to PyPI
165
+ (trusted publishing); `server.json` is the official MCP Registry manifest. Listed on
166
+ [Smithery](https://smithery.ai) too. Contributions welcome — see
167
+ [CONTRIBUTING.md](CONTRIBUTING.md) (the golden rules: zero dependencies at the core,
168
+ es/en strings everywhere, honest scope notes).
169
+
170
+ ## Roadmap
171
+
172
+ - [x] Rendered audit (computed contrast, target size 2.5.8, focus indicator)
173
+ - [x] 0-100 weighted score · ARIA validity · criterion explanations
174
+ - [x] Computed accessibility tree in snapshots + tree diff
175
+ - [x] SARIF export → findings as GitHub code-scanning / PR annotations (`a11y sarif`)
176
+ - [x] Honest dated badge as accessible SVG (`a11y_badge`)
177
+ - [x] Accessibility error budget: only NEW findings block (`a11y budget` + `examples/a11y-watch.yml`)
178
+ - [x] Multi-page same-domain crawl with aggregated scores (`pages` parameter)
179
+ - [x] Scheduled surveillance recipe (weekly audit + budget gate as a GitHub Action)
180
+ - [x] WCAG-EM conformance ladder (`conformance-wcagem` prompt + guided protocol)
181
+ - [x] Same-origin iframes in the rendered audit + :focus/:hover state contrast
182
+
183
+ ---
184
+
185
+ ## Author
186
+
187
+ **Jesús Quintana Fernández** ([jquin.net](https://jquin.net/)) — SEO/GEO consultant and
188
+ web-accessibility practitioner since 2003. MIT © 2026.
@@ -0,0 +1,167 @@
1
+ # a11y-toolkit — the accessibility layer for AI coding agents
2
+
3
+ [![CI](https://github.com/kinti/a11y-toolkit/actions/workflows/ci.yml/badge.svg)](https://github.com/kinti/a11y-toolkit/actions/workflows/ci.yml)
4
+ [![PyPI](https://img.shields.io/pypi/v/a11y-toolkit)](https://pypi.org/project/a11y-toolkit/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
6
+ [![Python 3.9+](https://img.shields.io/badge/python-3.9%2B-blue.svg)](pyproject.toml)
7
+ [![MCP](https://img.shields.io/badge/Model%20Context%20Protocol-server-purple)](https://modelcontextprotocol.io)
8
+ [![Smithery](https://smithery.ai/badge)](https://smithery.ai)
9
+
10
+ **12 MCP tools + 5 prompts + a skill** that give any AI agent (Claude, Cursor, Windsurf,
11
+ Codex…) the full WCAG 2.2 loop: **audit → fix → document → watch**. Zero dependencies at
12
+ its core; every finding ships with a concrete remediation your agent can apply.
13
+
14
+ Accessibility is not optional anymore: the **European Accessibility Act is in force since
15
+ June 2025**, ADA suits keep landing, and AI agents now write most of the web. This toolkit
16
+ makes "is it accessible?" a one-question ask — and "then fix it" a one-command job.
17
+
18
+ ## What no other a11y tool gives an agent
19
+
20
+ | Capability | axe-core / Lighthouse / pa11y | a11y-toolkit |
21
+ |---|---|---|
22
+ | Text contrast over **images/gradients** (pixel sampling of the real background, hostile-zone grid) | ✗ | ✓ |
23
+ | Legal **accessibility statements** (EAA / RD 1112/2018), accessible HTML, es/en | ✗ | ✓ |
24
+ | **Regression watch** between builds: accessible names + real tab-order diff | ✗ | ✓ |
25
+ | **Remediation text per finding**, written for an agent to apply | ✗ | ✓ |
26
+ | **Focus-order regression detection** | ✗ | ✓ |
27
+ | Runs with **zero dependencies** (stdlib only; Playwright optional for the deep pass) | heavy runtimes | ✓ |
28
+ | Screen-reader **aria-live announcement monitor** | ✗ | ✓ |
29
+ | **0-100 score** computed from weighted findings | ✓ (Lighthouse, subset of rules) | ✓ (fuller rule set) |
30
+ | **Criterion explanations** on demand for agents | ✗ | ✓ |
31
+ | Static core parity: ARIA validity, autocomplete 1.3.5, link purpose, duplicate ids | ✓ | ✓ |
32
+ | Output optimized for **MCP/LLM consumption** (JSON, severity-ranked, es/en) | ✗ | ✓ |
33
+
34
+ ## The tools (10)
35
+
36
+ | Tool | What it does |
37
+ |---|---|
38
+ | `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. |
39
+ | `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), all static checks on the live DOM. |
40
+ | `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. |
41
+ | `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. |
42
+ | *(rendered audit)* | adds **:focus/:hover state contrast** (disabled exempt) and **same-origin iframes** |
43
+ | `a11y_suggest_color` | Nearest opaque color (true RGB distance) reaching the target ratio (4.5 default). |
44
+ | `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. |
45
+ | `a11y_snapshot` | Interactive elements (tag, role, accessible name, href) + **real tab focus order** + the **computed accessibility tree** (what a screen reader announces). Requires Playwright. |
46
+ | `a11y_diff` | Regression diff between two snapshots: added/removed/renamed interactives, focus-order changes. |
47
+ | `a11y_diff_urls` | Snapshot two URLs and diff in one call (staging vs production). |
48
+ | `a11y_aria_live_snippet` | Injectable monitor logging every aria-live announcement (time, politeness, role, text) — what a screen reader would say, visible on screen. |
49
+ | `a11y_criterion` | Explains any WCAG 2.2 criterion in plain language: what it requires, typical failures, and which toolkit tool verifies it. |
50
+ | `a11y_badge` | Returns an **honest badge** as accessible SVG: score, date, scope ("automated screening"), never "conformant" — the anti-overclaim seal. |
51
+
52
+ **Prompts** (slash-commands in supporting clients): `audit-page` (full audit workflow +
53
+ what automation can't check), `fix-contrast`, `pre-deploy-check` (audit + diff → GO/NO-GO),
54
+ `declaration-eaa` (collects legal fields, generates).
55
+
56
+ ## Install
57
+
58
+ **Claude Code** (one command):
59
+
60
+ ```bash
61
+ claude mcp add a11y-toolkit -- uvx --from a11y-toolkit a11y-toolkit-mcp
62
+ ```
63
+
64
+ **Any MCP client with JSON config** (Claude Desktop, Cursor, Windsurf, VS Code…):
65
+
66
+ ```json
67
+ {
68
+ "mcpServers": {
69
+ "a11y-toolkit": {
70
+ "command": "uvx",
71
+ "args": ["--from", "a11y-toolkit", "a11y-toolkit-mcp"],
72
+ "timeoutMs": 60000
73
+ }
74
+ }
75
+ }
76
+ ```
77
+
78
+ Or from the repo without publishing:
79
+
80
+ ```json
81
+ { "mcpServers": { "a11y-toolkit": {
82
+ "command": "uvx", "args": ["--from", "git+https://github.com/kinti/a11y-toolkit", "a11y-toolkit-mcp"] } } }
83
+ ```
84
+
85
+ The rendered audit, snapshots and diffs use Playwright **if present**
86
+ (`pip install playwright && playwright install chromium`); everything else works with
87
+ zero dependencies.
88
+
89
+ ### The skill (teaches your agent when/how to use all of this)
90
+
91
+ ```bash
92
+ git clone https://github.com/kinti/a11y-toolkit && cd a11y-toolkit
93
+ ./skill/install-skill.sh # → ~/.zcode/skills and ~/.claude/skills
94
+ ```
95
+
96
+ ## CLI — same engine, one command
97
+
98
+ ```bash
99
+ a11y pair "#1f2328" "#fbfaf7" # contrast, per-criterion verdicts
100
+ a11y image hero.jpg --text "#ffffff" --region 120,40,420,90
101
+ a11y audit --url https://example.com --lang en # express static audit
102
+ a11y declaration --entidad "Acme" --url https://acme.example \
103
+ --estado parcial --marco eaa --lang en --output decl.html
104
+ a11y snapshot https://mysite --out before.json # before deploy (needs Playwright)
105
+ a11y diff before.json after.json # after deploy
106
+ ```
107
+
108
+ Run from a clone with `python3 a11y.py <subcommand>`; from PyPI with `uvx --from
109
+ a11y-toolkit a11y …`.
110
+
111
+ ### Watch it continuously (the deployment gate)
112
+
113
+ ```bash
114
+ a11y audit --url https://mysite --pages 5 > audit.json # light crawl
115
+ python3 -m a11ybudget --init < audit.json > budget.json # accept today's baseline
116
+ a11y budget --budget budget.json --audit audit.json # only NEW findings block (exit 2)
117
+ a11y sarif --from-audit audit.json -o a11y.sarif # GitHub code scanning format
118
+ ```
119
+
120
+ `examples/a11y-watch.yml` turns this into a weekly scheduled check that fails
121
+ on regressions and publishes the SARIF to code scanning.
122
+
123
+ ## Honesty, built in
124
+
125
+ Automation covers **~1/3 of WCAG** — every audit says so. The `audit-page` prompt and the
126
+ bundled skill then have the agent check what it *can* (keyboard operability, focus
127
+ visibility, zoom reflow, announced errors) using
128
+ [the manual checklist](skill/a11y-toolkit/references/wcag22-manual-checklist.md), and
129
+ recommend a screen-reader pass for the rest. A filter, not a verdict.
130
+
131
+ ## Security & scope
132
+
133
+ A **local** tool: runs on your machine as your user. `path` (image) and `output_path`
134
+ (statement) read/write local paths — use it in MCP clients you trust. Nothing leaves your
135
+ machine except the URL you explicitly audit.
136
+
137
+ ## Development
138
+
139
+ ```bash
140
+ python3 test_contrast.py && python3 test_audit.py && python3 test_dom.py && python3 test_mcp.py
141
+ ```
142
+
143
+ `test_dom.py` self-skips without Playwright. Releases: tag `vX.Y.Z` → CI publishes to PyPI
144
+ (trusted publishing); `server.json` is the official MCP Registry manifest. Listed on
145
+ [Smithery](https://smithery.ai) too. Contributions welcome — see
146
+ [CONTRIBUTING.md](CONTRIBUTING.md) (the golden rules: zero dependencies at the core,
147
+ es/en strings everywhere, honest scope notes).
148
+
149
+ ## Roadmap
150
+
151
+ - [x] Rendered audit (computed contrast, target size 2.5.8, focus indicator)
152
+ - [x] 0-100 weighted score · ARIA validity · criterion explanations
153
+ - [x] Computed accessibility tree in snapshots + tree diff
154
+ - [x] SARIF export → findings as GitHub code-scanning / PR annotations (`a11y sarif`)
155
+ - [x] Honest dated badge as accessible SVG (`a11y_badge`)
156
+ - [x] Accessibility error budget: only NEW findings block (`a11y budget` + `examples/a11y-watch.yml`)
157
+ - [x] Multi-page same-domain crawl with aggregated scores (`pages` parameter)
158
+ - [x] Scheduled surveillance recipe (weekly audit + budget gate as a GitHub Action)
159
+ - [x] WCAG-EM conformance ladder (`conformance-wcagem` prompt + guided protocol)
160
+ - [x] Same-origin iframes in the rendered audit + :focus/:hover state contrast
161
+
162
+ ---
163
+
164
+ ## Author
165
+
166
+ **Jesús Quintana Fernández** ([jquin.net](https://jquin.net/)) — SEO/GEO consultant and
167
+ web-accessibility practitioner since 2003. MIT © 2026.
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env python3
2
+ """a11y — un solo comando para todo el toolkit.
3
+
4
+ a11y pair "#texto" "#fondo" [--lang es|en]
5
+ a11y image ruta.jpg --text "#ffffff" [--region x,y,w,h] [--sample 4]
6
+ a11y audit --url https://cliente.web | --file pagina.html
7
+ a11y declaration --entidad "Nome" --url https://… --estado parcial [opciones]
8
+ a11y snapshot https://miweb --out antes.json # requiere Playwright
9
+ a11y diff antes.json despues.json
10
+ a11y audit --url https://web --pages 5 # crawl ligero mismo dominio
11
+ a11y sarif --url https://web -o a11y.sarif # para GitHub code scanning
12
+ a11y badge --score 92 --lang en --out badge.svg # insignia SVG honesta
13
+ a11y budget --budget budget.json --audit hoy.json # solo lo NUEVO bloquea
14
+ """
15
+
16
+ import sys
17
+
18
+ import a11yaudit
19
+ import a11ybadge
20
+ import a11ybudget
21
+ import a11ycrit
22
+ import a11ydiff
23
+ import a11ysarif
24
+ import contrast
25
+ import declaracion
26
+
27
+ SUBCOMANDOS = {
28
+ 'pair': (contrast, 'pair'),
29
+ 'image': (contrast, 'image'),
30
+ 'audit': (a11yaudit, None),
31
+ 'declaration': (declaracion, None),
32
+ 'snapshot': (a11ydiff, 'snapshot'),
33
+ 'diff': (a11ydiff, 'diff'),
34
+ 'criterion': (a11ycrit, None),
35
+ 'sarif': (a11ysarif, None),
36
+ 'badge': (a11ybadge, None),
37
+ 'budget': (a11ybudget, None),
38
+ }
39
+
40
+
41
+ def main(argv=None):
42
+ argv = list(sys.argv[1:] if argv is None else argv)
43
+ if not argv or argv[0] in ('-h', '--help') or argv[0] not in SUBCOMANDOS:
44
+ print(__doc__)
45
+ print('Subcomandos disponibles:', ', '.join(SUBCOMANDOS))
46
+ return 0 if argv and argv[0] in ('-h', '--help') else 1
47
+ modulo, sub = SUBCOMANDOS[argv[0]]
48
+ args = ([sub] + argv[1:]) if sub else argv[1:]
49
+ return modulo.main(args)
50
+
51
+
52
+ if __name__ == '__main__':
53
+ sys.exit(main())
@@ -0,0 +1,188 @@
1
+ Metadata-Version: 2.4
2
+ Name: a11y-toolkit
3
+ Version: 3.3.0
4
+ Summary: The accessibility layer for AI coding agents — MCP server + CLI for WCAG 2.2: express static audit, rendered audit (contrast, 2.5.8 target size, focus), contrast math (pairs, CSS names, hsl/rgba, text-over-image pixel sampling), EAA/RD 1112/2018 declarations, snapshot regression diffs, aria-live monitor. Zero dependencies at core; es/en.
5
+ Author: Jesús Quintana Fernández
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/kinti/a11y-toolkit
8
+ Project-URL: Issues, https://github.com/kinti/a11y-toolkit/issues
9
+ Project-URL: Changelog, https://github.com/kinti/a11y-toolkit/blob/main/CHANGELOG.md
10
+ Keywords: mcp,accessibility,a11y,wcag,wcag22,contrast,audit,eaa,ada,screen-reader,playwright,ai-agents
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Topic :: Software Development :: Quality Assurance
14
+ Classifier: Topic :: Internet :: WWW/HTTP :: Browsers
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Operating System :: OS Independent
17
+ Requires-Python: >=3.9
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Dynamic: license-file
21
+
22
+ # a11y-toolkit — the accessibility layer for AI coding agents
23
+
24
+ [![CI](https://github.com/kinti/a11y-toolkit/actions/workflows/ci.yml/badge.svg)](https://github.com/kinti/a11y-toolkit/actions/workflows/ci.yml)
25
+ [![PyPI](https://img.shields.io/pypi/v/a11y-toolkit)](https://pypi.org/project/a11y-toolkit/)
26
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
27
+ [![Python 3.9+](https://img.shields.io/badge/python-3.9%2B-blue.svg)](pyproject.toml)
28
+ [![MCP](https://img.shields.io/badge/Model%20Context%20Protocol-server-purple)](https://modelcontextprotocol.io)
29
+ [![Smithery](https://smithery.ai/badge)](https://smithery.ai)
30
+
31
+ **12 MCP tools + 5 prompts + a skill** that give any AI agent (Claude, Cursor, Windsurf,
32
+ Codex…) the full WCAG 2.2 loop: **audit → fix → document → watch**. Zero dependencies at
33
+ its core; every finding ships with a concrete remediation your agent can apply.
34
+
35
+ Accessibility is not optional anymore: the **European Accessibility Act is in force since
36
+ June 2025**, ADA suits keep landing, and AI agents now write most of the web. This toolkit
37
+ makes "is it accessible?" a one-question ask — and "then fix it" a one-command job.
38
+
39
+ ## What no other a11y tool gives an agent
40
+
41
+ | Capability | axe-core / Lighthouse / pa11y | a11y-toolkit |
42
+ |---|---|---|
43
+ | Text contrast over **images/gradients** (pixel sampling of the real background, hostile-zone grid) | ✗ | ✓ |
44
+ | Legal **accessibility statements** (EAA / RD 1112/2018), accessible HTML, es/en | ✗ | ✓ |
45
+ | **Regression watch** between builds: accessible names + real tab-order diff | ✗ | ✓ |
46
+ | **Remediation text per finding**, written for an agent to apply | ✗ | ✓ |
47
+ | **Focus-order regression detection** | ✗ | ✓ |
48
+ | Runs with **zero dependencies** (stdlib only; Playwright optional for the deep pass) | heavy runtimes | ✓ |
49
+ | Screen-reader **aria-live announcement monitor** | ✗ | ✓ |
50
+ | **0-100 score** computed from weighted findings | ✓ (Lighthouse, subset of rules) | ✓ (fuller rule set) |
51
+ | **Criterion explanations** on demand for agents | ✗ | ✓ |
52
+ | Static core parity: ARIA validity, autocomplete 1.3.5, link purpose, duplicate ids | ✓ | ✓ |
53
+ | Output optimized for **MCP/LLM consumption** (JSON, severity-ranked, es/en) | ✗ | ✓ |
54
+
55
+ ## The tools (10)
56
+
57
+ | Tool | What it does |
58
+ |---|---|
59
+ | `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. |
60
+ | `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), all static checks on the live DOM. |
61
+ | `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. |
62
+ | `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. |
63
+ | *(rendered audit)* | adds **:focus/:hover state contrast** (disabled exempt) and **same-origin iframes** |
64
+ | `a11y_suggest_color` | Nearest opaque color (true RGB distance) reaching the target ratio (4.5 default). |
65
+ | `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. |
66
+ | `a11y_snapshot` | Interactive elements (tag, role, accessible name, href) + **real tab focus order** + the **computed accessibility tree** (what a screen reader announces). Requires Playwright. |
67
+ | `a11y_diff` | Regression diff between two snapshots: added/removed/renamed interactives, focus-order changes. |
68
+ | `a11y_diff_urls` | Snapshot two URLs and diff in one call (staging vs production). |
69
+ | `a11y_aria_live_snippet` | Injectable monitor logging every aria-live announcement (time, politeness, role, text) — what a screen reader would say, visible on screen. |
70
+ | `a11y_criterion` | Explains any WCAG 2.2 criterion in plain language: what it requires, typical failures, and which toolkit tool verifies it. |
71
+ | `a11y_badge` | Returns an **honest badge** as accessible SVG: score, date, scope ("automated screening"), never "conformant" — the anti-overclaim seal. |
72
+
73
+ **Prompts** (slash-commands in supporting clients): `audit-page` (full audit workflow +
74
+ what automation can't check), `fix-contrast`, `pre-deploy-check` (audit + diff → GO/NO-GO),
75
+ `declaration-eaa` (collects legal fields, generates).
76
+
77
+ ## Install
78
+
79
+ **Claude Code** (one command):
80
+
81
+ ```bash
82
+ claude mcp add a11y-toolkit -- uvx --from a11y-toolkit a11y-toolkit-mcp
83
+ ```
84
+
85
+ **Any MCP client with JSON config** (Claude Desktop, Cursor, Windsurf, VS Code…):
86
+
87
+ ```json
88
+ {
89
+ "mcpServers": {
90
+ "a11y-toolkit": {
91
+ "command": "uvx",
92
+ "args": ["--from", "a11y-toolkit", "a11y-toolkit-mcp"],
93
+ "timeoutMs": 60000
94
+ }
95
+ }
96
+ }
97
+ ```
98
+
99
+ Or from the repo without publishing:
100
+
101
+ ```json
102
+ { "mcpServers": { "a11y-toolkit": {
103
+ "command": "uvx", "args": ["--from", "git+https://github.com/kinti/a11y-toolkit", "a11y-toolkit-mcp"] } } }
104
+ ```
105
+
106
+ The rendered audit, snapshots and diffs use Playwright **if present**
107
+ (`pip install playwright && playwright install chromium`); everything else works with
108
+ zero dependencies.
109
+
110
+ ### The skill (teaches your agent when/how to use all of this)
111
+
112
+ ```bash
113
+ git clone https://github.com/kinti/a11y-toolkit && cd a11y-toolkit
114
+ ./skill/install-skill.sh # → ~/.zcode/skills and ~/.claude/skills
115
+ ```
116
+
117
+ ## CLI — same engine, one command
118
+
119
+ ```bash
120
+ a11y pair "#1f2328" "#fbfaf7" # contrast, per-criterion verdicts
121
+ a11y image hero.jpg --text "#ffffff" --region 120,40,420,90
122
+ a11y audit --url https://example.com --lang en # express static audit
123
+ a11y declaration --entidad "Acme" --url https://acme.example \
124
+ --estado parcial --marco eaa --lang en --output decl.html
125
+ a11y snapshot https://mysite --out before.json # before deploy (needs Playwright)
126
+ a11y diff before.json after.json # after deploy
127
+ ```
128
+
129
+ Run from a clone with `python3 a11y.py <subcommand>`; from PyPI with `uvx --from
130
+ a11y-toolkit a11y …`.
131
+
132
+ ### Watch it continuously (the deployment gate)
133
+
134
+ ```bash
135
+ a11y audit --url https://mysite --pages 5 > audit.json # light crawl
136
+ python3 -m a11ybudget --init < audit.json > budget.json # accept today's baseline
137
+ a11y budget --budget budget.json --audit audit.json # only NEW findings block (exit 2)
138
+ a11y sarif --from-audit audit.json -o a11y.sarif # GitHub code scanning format
139
+ ```
140
+
141
+ `examples/a11y-watch.yml` turns this into a weekly scheduled check that fails
142
+ on regressions and publishes the SARIF to code scanning.
143
+
144
+ ## Honesty, built in
145
+
146
+ Automation covers **~1/3 of WCAG** — every audit says so. The `audit-page` prompt and the
147
+ bundled skill then have the agent check what it *can* (keyboard operability, focus
148
+ visibility, zoom reflow, announced errors) using
149
+ [the manual checklist](skill/a11y-toolkit/references/wcag22-manual-checklist.md), and
150
+ recommend a screen-reader pass for the rest. A filter, not a verdict.
151
+
152
+ ## Security & scope
153
+
154
+ A **local** tool: runs on your machine as your user. `path` (image) and `output_path`
155
+ (statement) read/write local paths — use it in MCP clients you trust. Nothing leaves your
156
+ machine except the URL you explicitly audit.
157
+
158
+ ## Development
159
+
160
+ ```bash
161
+ python3 test_contrast.py && python3 test_audit.py && python3 test_dom.py && python3 test_mcp.py
162
+ ```
163
+
164
+ `test_dom.py` self-skips without Playwright. Releases: tag `vX.Y.Z` → CI publishes to PyPI
165
+ (trusted publishing); `server.json` is the official MCP Registry manifest. Listed on
166
+ [Smithery](https://smithery.ai) too. Contributions welcome — see
167
+ [CONTRIBUTING.md](CONTRIBUTING.md) (the golden rules: zero dependencies at the core,
168
+ es/en strings everywhere, honest scope notes).
169
+
170
+ ## Roadmap
171
+
172
+ - [x] Rendered audit (computed contrast, target size 2.5.8, focus indicator)
173
+ - [x] 0-100 weighted score · ARIA validity · criterion explanations
174
+ - [x] Computed accessibility tree in snapshots + tree diff
175
+ - [x] SARIF export → findings as GitHub code-scanning / PR annotations (`a11y sarif`)
176
+ - [x] Honest dated badge as accessible SVG (`a11y_badge`)
177
+ - [x] Accessibility error budget: only NEW findings block (`a11y budget` + `examples/a11y-watch.yml`)
178
+ - [x] Multi-page same-domain crawl with aggregated scores (`pages` parameter)
179
+ - [x] Scheduled surveillance recipe (weekly audit + budget gate as a GitHub Action)
180
+ - [x] WCAG-EM conformance ladder (`conformance-wcagem` prompt + guided protocol)
181
+ - [x] Same-origin iframes in the rendered audit + :focus/:hover state contrast
182
+
183
+ ---
184
+
185
+ ## Author
186
+
187
+ **Jesús Quintana Fernández** ([jquin.net](https://jquin.net/)) — SEO/GEO consultant and
188
+ web-accessibility practitioner since 2003. MIT © 2026.
@@ -0,0 +1,20 @@
1
+ LICENSE
2
+ README.md
3
+ a11y.py
4
+ a11yaudit.py
5
+ a11ybadge.py
6
+ a11ybudget.py
7
+ a11ycrit.py
8
+ a11ydiff.py
9
+ a11ydom.py
10
+ a11ysarif.py
11
+ arialive_js.py
12
+ contrast.py
13
+ declaracion.py
14
+ pyproject.toml
15
+ server.py
16
+ a11y_toolkit.egg-info/PKG-INFO
17
+ a11y_toolkit.egg-info/SOURCES.txt
18
+ a11y_toolkit.egg-info/dependency_links.txt
19
+ a11y_toolkit.egg-info/entry_points.txt
20
+ a11y_toolkit.egg-info/top_level.txt
@@ -0,0 +1,6 @@
1
+ [console_scripts]
2
+ a11y = a11y:main
3
+ a11y-audit = a11yaudit:main
4
+ a11y-criterion = a11ycrit:main
5
+ a11y-sarif = a11ysarif:main
6
+ a11y-toolkit-mcp = server:main