@mcptoolshop/accessibility-suite 0.1.0

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.
Files changed (241) hide show
  1. package/.github/workflows/ci.yml +63 -0
  2. package/LICENSE +21 -0
  3. package/README.md +37 -0
  4. package/docs/prov-spec/.github/workflows/ci.yml +68 -0
  5. package/docs/prov-spec/CHANGELOG.md +69 -0
  6. package/docs/prov-spec/CODE_OF_CONDUCT.md +129 -0
  7. package/docs/prov-spec/CONFORMANCE_LEVELS.md +223 -0
  8. package/docs/prov-spec/CONTRIBUTING.md +145 -0
  9. package/docs/prov-spec/IMPLEMENTER_CHECKLIST.md +137 -0
  10. package/docs/prov-spec/LICENSE +21 -0
  11. package/docs/prov-spec/PRESS_RELEASE.md +74 -0
  12. package/docs/prov-spec/README.md +182 -0
  13. package/docs/prov-spec/SETUP.md +135 -0
  14. package/docs/prov-spec/WHY.md +86 -0
  15. package/docs/prov-spec/examples/artifact.example.json +14 -0
  16. package/docs/prov-spec/examples/artifact.ref.example.json +9 -0
  17. package/docs/prov-spec/examples/evidence.example.json +6 -0
  18. package/docs/prov-spec/examples/mcp.envelope.example.json +97 -0
  19. package/docs/prov-spec/examples/mcp.request.example.json +28 -0
  20. package/docs/prov-spec/examples/prov.record.example.json +35 -0
  21. package/docs/prov-spec/interop/PROOF_NODE_ENGINE.md +114 -0
  22. package/docs/prov-spec/spec/MCP_COMPATIBILITY.md +241 -0
  23. package/docs/prov-spec/spec/PROV_METHODS_CATALOG.md +142 -0
  24. package/docs/prov-spec/spec/PROV_METHODS_SPEC.md +397 -0
  25. package/docs/prov-spec/spec/methods.json +213 -0
  26. package/docs/prov-spec/spec/schemas/artifact.ref.schema.v0.1.json +58 -0
  27. package/docs/prov-spec/spec/schemas/artifact.schema.v0.1.json +61 -0
  28. package/docs/prov-spec/spec/schemas/assist.request.schema.v0.1.json +52 -0
  29. package/docs/prov-spec/spec/schemas/assist.response.schema.v0.1.json +70 -0
  30. package/docs/prov-spec/spec/schemas/cli.error.schema.v0.1.json +78 -0
  31. package/docs/prov-spec/spec/schemas/evidence.schema.v0.1.json +37 -0
  32. package/docs/prov-spec/spec/schemas/mcp.envelope.schema.v0.1.json +141 -0
  33. package/docs/prov-spec/spec/schemas/mcp.request.schema.v0.1.json +79 -0
  34. package/docs/prov-spec/spec/schemas/methods.schema.json +93 -0
  35. package/docs/prov-spec/spec/schemas/prov-capabilities.schema.json +122 -0
  36. package/docs/prov-spec/spec/schemas/prov.record.schema.v0.1.json +133 -0
  37. package/docs/prov-spec/spec/vectors/adapter.wrap.envelope_v0_1/expected.json +4 -0
  38. package/docs/prov-spec/spec/vectors/adapter.wrap.envelope_v0_1/input.json +1 -0
  39. package/docs/prov-spec/spec/vectors/adapter.wrap.envelope_v0_1/negative/double_wrapped.json +14 -0
  40. package/docs/prov-spec/spec/vectors/adapter.wrap.envelope_v0_1/negative/wrong_schema_version.json +11 -0
  41. package/docs/prov-spec/spec/vectors/engine.extract.evidence.json_pointer/expected.json +24 -0
  42. package/docs/prov-spec/spec/vectors/engine.extract.evidence.json_pointer/input.json +8 -0
  43. package/docs/prov-spec/spec/vectors/integrity.digest.sha256/expected.json +7 -0
  44. package/docs/prov-spec/spec/vectors/integrity.digest.sha256/input.json +1 -0
  45. package/docs/prov-spec/spec/vectors/integrity.digest.sha256/negative/non_hex_chars.json +16 -0
  46. package/docs/prov-spec/spec/vectors/integrity.digest.sha256/negative/uppercase_hex.json +16 -0
  47. package/docs/prov-spec/spec/vectors/integrity.digest.sha256/negative/wrong_length.json +16 -0
  48. package/docs/prov-spec/spec/vectors/method_id_syntax/negative/hyphen_separator.json +8 -0
  49. package/docs/prov-spec/spec/vectors/method_id_syntax/negative/reserved_namespace.json +8 -0
  50. package/docs/prov-spec/spec/vectors/method_id_syntax/negative/starts_with_digit.json +8 -0
  51. package/docs/prov-spec/spec/vectors/method_id_syntax/negative/uppercase.json +8 -0
  52. package/docs/prov-spec/spec/vectors/method_id_syntax/positive/valid_ids.json +18 -0
  53. package/docs/prov-spec/tools/python/prov_validator.py +428 -0
  54. package/examples/a11y-demo-site/.github/workflows/a11y-artifacts.yml +81 -0
  55. package/examples/a11y-demo-site/.github/workflows/a11y.yml +34 -0
  56. package/examples/a11y-demo-site/CODE_OF_CONDUCT.md +129 -0
  57. package/examples/a11y-demo-site/CONTRIBUTING.md +83 -0
  58. package/examples/a11y-demo-site/LICENSE +21 -0
  59. package/examples/a11y-demo-site/README.md +155 -0
  60. package/examples/a11y-demo-site/html/contact.html +15 -0
  61. package/examples/a11y-demo-site/html/index.html +20 -0
  62. package/examples/a11y-demo-site/scripts/a11y.sh +20 -0
  63. package/package.json +26 -0
  64. package/src/a11y-assist/.github/workflows/publish.yml +52 -0
  65. package/src/a11y-assist/.github/workflows/test.yml +30 -0
  66. package/src/a11y-assist/A11Y_ASSIST_TEST_COVERAGE_REQUIREMENTS.md +104 -0
  67. package/src/a11y-assist/CODE_OF_CONDUCT.md +129 -0
  68. package/src/a11y-assist/CONTRIBUTING.md +98 -0
  69. package/src/a11y-assist/ENGINE.md +363 -0
  70. package/src/a11y-assist/LICENSE +21 -0
  71. package/src/a11y-assist/PRESS_RELEASE.md +71 -0
  72. package/src/a11y-assist/QUICKSTART.md +101 -0
  73. package/src/a11y-assist/README.md +192 -0
  74. package/src/a11y-assist/RELEASE_NOTES.md +319 -0
  75. package/src/a11y-assist/a11y_assist/__init__.py +3 -0
  76. package/src/a11y-assist/a11y_assist/cli.py +599 -0
  77. package/src/a11y-assist/a11y_assist/from_cli_error.py +149 -0
  78. package/src/a11y-assist/a11y_assist/guard.py +444 -0
  79. package/src/a11y-assist/a11y_assist/ingest.py +407 -0
  80. package/src/a11y-assist/a11y_assist/methods.py +137 -0
  81. package/src/a11y-assist/a11y_assist/parse_raw.py +71 -0
  82. package/src/a11y-assist/a11y_assist/profiles/__init__.py +29 -0
  83. package/src/a11y-assist/a11y_assist/profiles/cognitive_load.py +245 -0
  84. package/src/a11y-assist/a11y_assist/profiles/cognitive_load_render.py +86 -0
  85. package/src/a11y-assist/a11y_assist/profiles/dyslexia.py +144 -0
  86. package/src/a11y-assist/a11y_assist/profiles/dyslexia_render.py +77 -0
  87. package/src/a11y-assist/a11y_assist/profiles/plain_language.py +119 -0
  88. package/src/a11y-assist/a11y_assist/profiles/plain_language_render.py +66 -0
  89. package/src/a11y-assist/a11y_assist/profiles/screen_reader.py +348 -0
  90. package/src/a11y-assist/a11y_assist/profiles/screen_reader_render.py +89 -0
  91. package/src/a11y-assist/a11y_assist/render.py +95 -0
  92. package/src/a11y-assist/a11y_assist/schemas/assist.request.schema.v0.1.json +52 -0
  93. package/src/a11y-assist/a11y_assist/schemas/assist.response.schema.v0.1.json +70 -0
  94. package/src/a11y-assist/a11y_assist/schemas/cli.error.schema.v0.1.json +78 -0
  95. package/src/a11y-assist/a11y_assist/storage.py +31 -0
  96. package/src/a11y-assist/pyproject.toml +60 -0
  97. package/src/a11y-assist/tests/__init__.py +1 -0
  98. package/src/a11y-assist/tests/fixtures/base_inputs/cli_error_high.json +18 -0
  99. package/src/a11y-assist/tests/fixtures/base_inputs/cli_error_medium.json +16 -0
  100. package/src/a11y-assist/tests/fixtures/base_inputs/raw_text_low.txt +3 -0
  101. package/src/a11y-assist/tests/fixtures/cli_error_good.json +9 -0
  102. package/src/a11y-assist/tests/fixtures/cli_error_missing_id.json +7 -0
  103. package/src/a11y-assist/tests/fixtures/cli_error_string_format.json +7 -0
  104. package/src/a11y-assist/tests/fixtures/expected/cognitive_load_high.txt +20 -0
  105. package/src/a11y-assist/tests/fixtures/expected/dyslexia_high.txt +20 -0
  106. package/src/a11y-assist/tests/fixtures/expected/lowvision_high.txt +18 -0
  107. package/src/a11y-assist/tests/fixtures/expected/plain_language_high.txt +14 -0
  108. package/src/a11y-assist/tests/fixtures/expected/screen_reader_high.txt +19 -0
  109. package/src/a11y-assist/tests/fixtures/golden_screen_reader_cli_error.txt +16 -0
  110. package/src/a11y-assist/tests/fixtures/golden_screen_reader_raw_no_id.txt +14 -0
  111. package/src/a11y-assist/tests/fixtures/golden_screen_reader_raw_with_id.txt +14 -0
  112. package/src/a11y-assist/tests/fixtures/raw_good.txt +11 -0
  113. package/src/a11y-assist/tests/fixtures/raw_no_id.txt +2 -0
  114. package/src/a11y-assist/tests/test_cognitive_load.py +469 -0
  115. package/src/a11y-assist/tests/test_dyslexia.py +337 -0
  116. package/src/a11y-assist/tests/test_explain.py +74 -0
  117. package/src/a11y-assist/tests/test_golden.py +127 -0
  118. package/src/a11y-assist/tests/test_guard.py +819 -0
  119. package/src/a11y-assist/tests/test_guard_integration.py +457 -0
  120. package/src/a11y-assist/tests/test_ingest.py +311 -0
  121. package/src/a11y-assist/tests/test_methods_metadata.py +236 -0
  122. package/src/a11y-assist/tests/test_plain_language.py +348 -0
  123. package/src/a11y-assist/tests/test_render.py +117 -0
  124. package/src/a11y-assist/tests/test_screen_reader.py +703 -0
  125. package/src/a11y-assist/tests/test_storage_last.py +61 -0
  126. package/src/a11y-assist/tests/test_triage.py +86 -0
  127. package/src/a11y-ci/.github/workflows/ci.yml +43 -0
  128. package/src/a11y-ci/.github/workflows/test.yml +30 -0
  129. package/src/a11y-ci/A11Y_CI_TEST_COVERAGE_REQUIREMENTS.md +94 -0
  130. package/src/a11y-ci/CODE_OF_CONDUCT.md +129 -0
  131. package/src/a11y-ci/CONTRIBUTING.md +142 -0
  132. package/src/a11y-ci/LICENSE +21 -0
  133. package/src/a11y-ci/README.md +105 -0
  134. package/src/a11y-ci/a11y_ci/__init__.py +3 -0
  135. package/src/a11y-ci/a11y_ci/allowlist.py +83 -0
  136. package/src/a11y-ci/a11y_ci/cli.py +145 -0
  137. package/src/a11y-ci/a11y_ci/gate.py +131 -0
  138. package/src/a11y-ci/a11y_ci/render.py +48 -0
  139. package/src/a11y-ci/a11y_ci/schemas/allowlist.schema.json +24 -0
  140. package/src/a11y-ci/a11y_ci/scorecard.py +99 -0
  141. package/src/a11y-ci/npm/package.json +35 -0
  142. package/src/a11y-ci/pyproject.toml +64 -0
  143. package/src/a11y-ci/tests/__init__.py +1 -0
  144. package/src/a11y-ci/tests/fixtures/allowlist_expired.json +10 -0
  145. package/src/a11y-ci/tests/fixtures/allowlist_ok.json +10 -0
  146. package/src/a11y-ci/tests/fixtures/baseline_ok.json +7 -0
  147. package/src/a11y-ci/tests/fixtures/current_fail.json +6 -0
  148. package/src/a11y-ci/tests/fixtures/current_ok.json +6 -0
  149. package/src/a11y-ci/tests/fixtures/current_regresses.json +7 -0
  150. package/src/a11y-ci/tests/test_gate.py +134 -0
  151. package/src/a11y-evidence-engine/.github/workflows/ci.yml +53 -0
  152. package/src/a11y-evidence-engine/CODE_OF_CONDUCT.md +129 -0
  153. package/src/a11y-evidence-engine/CONTRIBUTING.md +128 -0
  154. package/src/a11y-evidence-engine/LICENSE +21 -0
  155. package/src/a11y-evidence-engine/README.md +71 -0
  156. package/src/a11y-evidence-engine/bin/a11y-engine.js +11 -0
  157. package/src/a11y-evidence-engine/fixtures/bad/button-no-name.html +30 -0
  158. package/src/a11y-evidence-engine/fixtures/bad/img-missing-alt.html +19 -0
  159. package/src/a11y-evidence-engine/fixtures/bad/input-missing-label.html +26 -0
  160. package/src/a11y-evidence-engine/fixtures/bad/missing-lang.html +11 -0
  161. package/src/a11y-evidence-engine/fixtures/good/index.html +29 -0
  162. package/src/a11y-evidence-engine/package-lock.json +109 -0
  163. package/src/a11y-evidence-engine/package.json +45 -0
  164. package/src/a11y-evidence-engine/src/cli.js +74 -0
  165. package/src/a11y-evidence-engine/src/evidence/canonicalize.js +52 -0
  166. package/src/a11y-evidence-engine/src/evidence/json_pointer.js +34 -0
  167. package/src/a11y-evidence-engine/src/evidence/prov_emit.js +153 -0
  168. package/src/a11y-evidence-engine/src/fswalk.js +56 -0
  169. package/src/a11y-evidence-engine/src/html_parse.js +117 -0
  170. package/src/a11y-evidence-engine/src/ids.js +53 -0
  171. package/src/a11y-evidence-engine/src/rules/document_missing_lang.js +50 -0
  172. package/src/a11y-evidence-engine/src/rules/form_control_missing_label.js +105 -0
  173. package/src/a11y-evidence-engine/src/rules/img_missing_alt.js +77 -0
  174. package/src/a11y-evidence-engine/src/rules/index.js +37 -0
  175. package/src/a11y-evidence-engine/src/rules/interactive_missing_name.js +129 -0
  176. package/src/a11y-evidence-engine/src/scan.js +128 -0
  177. package/src/a11y-evidence-engine/test/scan.test.js +149 -0
  178. package/src/a11y-evidence-engine/test/vectors.test.js +200 -0
  179. package/src/a11y-lint/.github/workflows/ci.yml +46 -0
  180. package/src/a11y-lint/.github/workflows/test.yml +34 -0
  181. package/src/a11y-lint/CODE_OF_CONDUCT.md +129 -0
  182. package/src/a11y-lint/CONTRIBUTING.md +70 -0
  183. package/src/a11y-lint/GOVERNANCE.md +57 -0
  184. package/src/a11y-lint/LICENSE +21 -0
  185. package/src/a11y-lint/PRESS_RELEASE.md +50 -0
  186. package/src/a11y-lint/README.md +276 -0
  187. package/src/a11y-lint/RELEASE_NOTES.md +57 -0
  188. package/src/a11y-lint/RELEASING.md +57 -0
  189. package/src/a11y-lint/a11y_lint/__init__.py +64 -0
  190. package/src/a11y-lint/a11y_lint/cli.py +319 -0
  191. package/src/a11y-lint/a11y_lint/errors.py +252 -0
  192. package/src/a11y-lint/a11y_lint/render.py +293 -0
  193. package/src/a11y-lint/a11y_lint/report_md.py +289 -0
  194. package/src/a11y-lint/a11y_lint/scan_cli_text.py +434 -0
  195. package/src/a11y-lint/a11y_lint/schemas/cli.error.schema.v0.1.json +83 -0
  196. package/src/a11y-lint/a11y_lint/scorecard.py +244 -0
  197. package/src/a11y-lint/a11y_lint/validate.py +225 -0
  198. package/src/a11y-lint/pyproject.toml +75 -0
  199. package/src/a11y-lint/tests/__init__.py +1 -0
  200. package/src/a11y-lint/tests/test_cli.py +200 -0
  201. package/src/a11y-lint/tests/test_errors.py +188 -0
  202. package/src/a11y-lint/tests/test_render.py +202 -0
  203. package/src/a11y-lint/tests/test_report_md.py +188 -0
  204. package/src/a11y-lint/tests/test_scan_cli_text.py +290 -0
  205. package/src/a11y-lint/tests/test_scorecard.py +195 -0
  206. package/src/a11y-lint/tests/test_validate.py +257 -0
  207. package/src/a11y-mcp-tools/.github/workflows/ci.yml +53 -0
  208. package/src/a11y-mcp-tools/CODE_OF_CONDUCT.md +129 -0
  209. package/src/a11y-mcp-tools/CONTRIBUTING.md +136 -0
  210. package/src/a11y-mcp-tools/LICENSE +21 -0
  211. package/src/a11y-mcp-tools/PROV_METHODS_CATALOG.md +104 -0
  212. package/src/a11y-mcp-tools/README.md +168 -0
  213. package/src/a11y-mcp-tools/bin/cli.js +452 -0
  214. package/src/a11y-mcp-tools/bin/server.js +244 -0
  215. package/src/a11y-mcp-tools/fixtures/requests/a11y.diagnose.ok.json +27 -0
  216. package/src/a11y-mcp-tools/fixtures/requests/a11y.evidence.ok.json +25 -0
  217. package/src/a11y-mcp-tools/fixtures/responses/a11y.diagnose.ok.json +139 -0
  218. package/src/a11y-mcp-tools/fixtures/responses/a11y.diagnose.provenance_fail.json +13 -0
  219. package/src/a11y-mcp-tools/fixtures/responses/a11y.evidence.ok.json +88 -0
  220. package/src/a11y-mcp-tools/package-lock.json +189 -0
  221. package/src/a11y-mcp-tools/package.json +49 -0
  222. package/src/a11y-mcp-tools/src/envelope.js +197 -0
  223. package/src/a11y-mcp-tools/src/index.js +9 -0
  224. package/src/a11y-mcp-tools/src/schemas/artifact.js +85 -0
  225. package/src/a11y-mcp-tools/src/schemas/diagnosis.schema.v0.1.json +137 -0
  226. package/src/a11y-mcp-tools/src/schemas/envelope.schema.v0.1.json +108 -0
  227. package/src/a11y-mcp-tools/src/schemas/evidence.bundle.schema.v0.1.json +129 -0
  228. package/src/a11y-mcp-tools/src/schemas/evidence.js +97 -0
  229. package/src/a11y-mcp-tools/src/schemas/index.js +11 -0
  230. package/src/a11y-mcp-tools/src/schemas/provenance.js +140 -0
  231. package/src/a11y-mcp-tools/src/schemas/tools/a11y.diagnose.request.schema.v0.1.json +77 -0
  232. package/src/a11y-mcp-tools/src/schemas/tools/a11y.diagnose.response.schema.v0.1.json +50 -0
  233. package/src/a11y-mcp-tools/src/schemas/tools/a11y.evidence.request.schema.v0.1.json +120 -0
  234. package/src/a11y-mcp-tools/src/schemas/tools/a11y.evidence.response.schema.v0.1.json +50 -0
  235. package/src/a11y-mcp-tools/src/tools/diagnose.js +597 -0
  236. package/src/a11y-mcp-tools/src/tools/evidence.js +481 -0
  237. package/src/a11y-mcp-tools/src/tools/index.js +10 -0
  238. package/src/a11y-mcp-tools/test/contract.test.mjs +154 -0
  239. package/src/a11y-mcp-tools/test/diagnose.test.js +485 -0
  240. package/src/a11y-mcp-tools/test/evidence.test.js +183 -0
  241. package/src/a11y-mcp-tools/test/schema.test.js +327 -0
@@ -0,0 +1,244 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ /**
5
+ * MCP Server for a11y tools.
6
+ *
7
+ * Implements the Model Context Protocol for:
8
+ * - a11y.evidence: Evidence capture
9
+ * - a11y.diagnose: Accessibility diagnosis
10
+ *
11
+ * Supports MCP envelope v0.1 for requests/responses.
12
+ */
13
+
14
+ const readline = require("readline");
15
+ const { evidence, diagnose, tools } = require("../src/tools/index.js");
16
+ const {
17
+ ENVELOPE_VERSION,
18
+ ERROR_CODES,
19
+ generateRequestId,
20
+ createResponseEnvelope,
21
+ createErrorEnvelope,
22
+ normalizeRequest,
23
+ } = require("../src/envelope.js");
24
+
25
+ // In-memory bundle store for the session
26
+ const bundleStore = {};
27
+
28
+ /**
29
+ * Handle incoming MCP request.
30
+ */
31
+ async function handleRequest(request) {
32
+ const { id, method, params } = request;
33
+
34
+ try {
35
+ switch (method) {
36
+ case "initialize":
37
+ return {
38
+ jsonrpc: "2.0",
39
+ id,
40
+ result: {
41
+ protocolVersion: "2024-11-05",
42
+ capabilities: {
43
+ tools: {},
44
+ },
45
+ serverInfo: {
46
+ name: "a11y-mcp-tools",
47
+ version: "0.2.0",
48
+ },
49
+ },
50
+ };
51
+
52
+ case "tools/list":
53
+ return {
54
+ jsonrpc: "2.0",
55
+ id,
56
+ result: {
57
+ tools: tools.map((t) => ({
58
+ name: t.name,
59
+ description: t.description,
60
+ inputSchema: t.inputSchema,
61
+ })),
62
+ },
63
+ };
64
+
65
+ case "tools/call":
66
+ return await handleToolCall(id, params);
67
+
68
+ default:
69
+ return {
70
+ jsonrpc: "2.0",
71
+ id,
72
+ error: {
73
+ code: -32601,
74
+ message: `Method not found: ${method}`,
75
+ },
76
+ };
77
+ }
78
+ } catch (err) {
79
+ return {
80
+ jsonrpc: "2.0",
81
+ id,
82
+ error: {
83
+ code: -32603,
84
+ message: err.message,
85
+ },
86
+ };
87
+ }
88
+ }
89
+
90
+ /**
91
+ * Handle tool call with envelope support.
92
+ */
93
+ async function handleToolCall(id, params) {
94
+ const { name, arguments: args } = params;
95
+
96
+ // Normalize to envelope format (supports both raw and envelope input)
97
+ const envelope = normalizeRequest(args, name);
98
+ const requestId = envelope.mcp?.request_id || generateRequestId();
99
+ const input = envelope.input || args;
100
+
101
+ let result;
102
+ let responseEnvelope;
103
+
104
+ try {
105
+ switch (name) {
106
+ case "a11y.evidence":
107
+ result = await evidence.execute(input);
108
+ if (result.ok) {
109
+ // Store bundle for later diagnosis
110
+ if (result.bundle) {
111
+ bundleStore[result.bundle.bundle_id] = result.bundle;
112
+ }
113
+ responseEnvelope = createResponseEnvelope(requestId, name, {
114
+ bundle: result.bundle,
115
+ });
116
+ } else {
117
+ responseEnvelope = createErrorEnvelope(
118
+ requestId,
119
+ name,
120
+ result.error?.code || ERROR_CODES.CAPTURE_FAILED,
121
+ result.error?.message || "Evidence capture failed",
122
+ result.error?.fix
123
+ );
124
+ }
125
+ break;
126
+
127
+ case "a11y.diagnose":
128
+ // Check if bundle_id is provided and resolve from store
129
+ if (input.bundle_id && !input.bundle) {
130
+ const storedBundle = bundleStore[input.bundle_id];
131
+ if (!storedBundle) {
132
+ responseEnvelope = createErrorEnvelope(
133
+ requestId,
134
+ name,
135
+ ERROR_CODES.BUNDLE_NOT_FOUND,
136
+ `Bundle not found: ${input.bundle_id}`,
137
+ "Capture evidence first using a11y.evidence, or provide bundle inline."
138
+ );
139
+ break;
140
+ }
141
+ input.bundle = storedBundle;
142
+ }
143
+
144
+ result = await diagnose.execute(input, bundleStore);
145
+ if (result.ok) {
146
+ responseEnvelope = createResponseEnvelope(requestId, name, {
147
+ diagnosis: result.diagnosis,
148
+ });
149
+ } else {
150
+ responseEnvelope = createErrorEnvelope(
151
+ requestId,
152
+ name,
153
+ result.error?.code || ERROR_CODES.INTERNAL_ERROR,
154
+ result.error?.message || "Diagnosis failed",
155
+ result.error?.fix
156
+ );
157
+ }
158
+ break;
159
+
160
+ default:
161
+ return {
162
+ jsonrpc: "2.0",
163
+ id,
164
+ error: {
165
+ code: -32602,
166
+ message: `Unknown tool: ${name}`,
167
+ },
168
+ };
169
+ }
170
+
171
+ return {
172
+ jsonrpc: "2.0",
173
+ id,
174
+ result: {
175
+ content: [
176
+ {
177
+ type: "text",
178
+ text: JSON.stringify(responseEnvelope, null, 2),
179
+ },
180
+ ],
181
+ },
182
+ };
183
+ } catch (err) {
184
+ const errorEnvelope = createErrorEnvelope(
185
+ requestId,
186
+ name,
187
+ ERROR_CODES.INTERNAL_ERROR,
188
+ err.message
189
+ );
190
+
191
+ return {
192
+ jsonrpc: "2.0",
193
+ id,
194
+ result: {
195
+ content: [
196
+ {
197
+ type: "text",
198
+ text: JSON.stringify(errorEnvelope, null, 2),
199
+ },
200
+ ],
201
+ },
202
+ };
203
+ }
204
+ }
205
+
206
+ /**
207
+ * Main entry point.
208
+ */
209
+ async function main() {
210
+ const rl = readline.createInterface({
211
+ input: process.stdin,
212
+ output: process.stdout,
213
+ terminal: false,
214
+ });
215
+
216
+ console.error("a11y-mcp-tools server started (v0.2.0, envelope: " + ENVELOPE_VERSION + ")");
217
+
218
+ for await (const line of rl) {
219
+ if (!line.trim()) continue;
220
+
221
+ try {
222
+ const request = JSON.parse(line);
223
+ const response = await handleRequest(request);
224
+ console.log(JSON.stringify(response));
225
+ } catch (err) {
226
+ console.error("Parse error:", err.message);
227
+ console.log(
228
+ JSON.stringify({
229
+ jsonrpc: "2.0",
230
+ id: null,
231
+ error: {
232
+ code: -32700,
233
+ message: "Parse error",
234
+ },
235
+ })
236
+ );
237
+ }
238
+ }
239
+ }
240
+
241
+ main().catch((err) => {
242
+ console.error("Fatal error:", err);
243
+ process.exit(1);
244
+ });
@@ -0,0 +1,27 @@
1
+ {
2
+ "mcp": {
3
+ "envelope": "mcp.envelope_v0_1",
4
+ "request_id": "req_fixture_diagnose_001",
5
+ "tool": "a11y.diagnose",
6
+ "client": {
7
+ "name": "a11y-cli",
8
+ "version": "0.2.0"
9
+ }
10
+ },
11
+ "input": {
12
+ "bundle_id": "bundle:fixture:9b6d3c01",
13
+ "artifacts": ["artifact:dom:index", "artifact:dom:contact"],
14
+ "profile": "wcag-2.2-aa",
15
+ "rules": {
16
+ "include": ["lang", "alt", "button-name", "link-name", "label"],
17
+ "exclude": []
18
+ },
19
+ "output": {
20
+ "include_fix_guidance": true,
21
+ "include_evidence": true
22
+ },
23
+ "integrity": {
24
+ "verify_provenance": true
25
+ }
26
+ }
27
+ }
@@ -0,0 +1,25 @@
1
+ {
2
+ "mcp": {
3
+ "envelope": "mcp.envelope_v0_1",
4
+ "request_id": "req_fixture_evidence_001",
5
+ "tool": "a11y.evidence",
6
+ "client": {
7
+ "name": "a11y-cli",
8
+ "version": "0.2.0"
9
+ }
10
+ },
11
+ "input": {
12
+ "targets": [
13
+ { "kind": "file", "path": "html/index.html" },
14
+ { "kind": "file", "path": "html/contact.html" },
15
+ { "kind": "cli_log", "path": "runs/latest.log" }
16
+ ],
17
+ "capture": {
18
+ "html": { "canonicalize": true, "strip_dynamic": true },
19
+ "dom": { "snapshot": true, "include_css_selectors": true },
20
+ "environment": { "include": ["os", "node", "tool_versions"] }
21
+ },
22
+ "integrity": { "hash": "sha256" },
23
+ "labels": ["a11y", "baseline", "wcag-2.2-aa"]
24
+ }
25
+ }
@@ -0,0 +1,139 @@
1
+ {
2
+ "mcp": {
3
+ "envelope": "mcp.envelope_v0_1",
4
+ "request_id": "req_fixture_diagnose_001",
5
+ "tool": "a11y.diagnose",
6
+ "ok": true
7
+ },
8
+ "result": {
9
+ "diagnosis": {
10
+ "summary": {
11
+ "profile": "wcag-2.2-aa",
12
+ "targets": 2,
13
+ "findings_total": 4,
14
+ "severity_counts": {
15
+ "critical": 0,
16
+ "high": 3,
17
+ "medium": 1,
18
+ "low": 0
19
+ },
20
+ "rules_applied": ["lang", "alt", "button-name", "link-name", "label"]
21
+ },
22
+ "findings": [
23
+ {
24
+ "id": "a11y.lang.missing",
25
+ "wcag": "wcag.3.1.1",
26
+ "severity": "high",
27
+ "message": "Document is missing a lang attribute on <html>.",
28
+ "targets": [
29
+ {
30
+ "artifact_id": "artifact:dom:index",
31
+ "json_pointer": "/nodes/0",
32
+ "selector": "html",
33
+ "snippet": "<html>"
34
+ }
35
+ ],
36
+ "fix": {
37
+ "safe": true,
38
+ "description": "Add lang attribute to the html element",
39
+ "patch": {
40
+ "action": "add_attribute",
41
+ "target": "html",
42
+ "value": "lang=\"en\""
43
+ },
44
+ "wcag_ref": "https://www.w3.org/WAI/WCAG22/Understanding/language-of-page.html"
45
+ }
46
+ },
47
+ {
48
+ "id": "a11y.img.missing_alt",
49
+ "wcag": "wcag.1.1.1",
50
+ "severity": "high",
51
+ "message": "Image is missing alt attribute.",
52
+ "targets": [
53
+ {
54
+ "artifact_id": "artifact:dom:index",
55
+ "json_pointer": "/nodes/5",
56
+ "selector": "img",
57
+ "snippet": "<img src=\"hero.jpg\">"
58
+ }
59
+ ],
60
+ "fix": {
61
+ "safe": true,
62
+ "description": "Add descriptive alt text or alt=\"\" for decorative images",
63
+ "patch": {
64
+ "action": "add_attribute",
65
+ "target": "img",
66
+ "value": "alt=\"[describe image]\""
67
+ },
68
+ "wcag_ref": "https://www.w3.org/WAI/WCAG22/Understanding/non-text-content.html"
69
+ }
70
+ },
71
+ {
72
+ "id": "a11y.button.missing_name",
73
+ "wcag": "wcag.4.1.2",
74
+ "severity": "high",
75
+ "message": "Button has no accessible name.",
76
+ "targets": [
77
+ {
78
+ "artifact_id": "artifact:dom:contact",
79
+ "json_pointer": "/nodes/12",
80
+ "selector": "button",
81
+ "snippet": "<button><i class=\"icon-send\"></i></button>"
82
+ }
83
+ ],
84
+ "fix": {
85
+ "safe": true,
86
+ "description": "Add aria-label or visible text content",
87
+ "patch": {
88
+ "action": "add_attribute",
89
+ "target": "button",
90
+ "value": "aria-label=\"Send message\""
91
+ },
92
+ "wcag_ref": "https://www.w3.org/WAI/WCAG22/Understanding/name-role-value.html"
93
+ }
94
+ },
95
+ {
96
+ "id": "a11y.input.missing_label",
97
+ "wcag": "wcag.1.3.1",
98
+ "severity": "medium",
99
+ "message": "Form input has no associated label.",
100
+ "targets": [
101
+ {
102
+ "artifact_id": "artifact:dom:contact",
103
+ "json_pointer": "/nodes/8",
104
+ "selector": "input[type=\"email\"]",
105
+ "snippet": "<input type=\"email\" name=\"email\">"
106
+ }
107
+ ],
108
+ "fix": {
109
+ "safe": true,
110
+ "description": "Add label element with for attribute or aria-label",
111
+ "patch": {
112
+ "action": "add_attribute",
113
+ "target": "input",
114
+ "value": "aria-label=\"Email address\""
115
+ },
116
+ "wcag_ref": "https://www.w3.org/WAI/WCAG22/Understanding/info-and-relationships.html"
117
+ }
118
+ }
119
+ ],
120
+ "provenance": {
121
+ "record_id": "prov:record:fixture-diag-001",
122
+ "methods": [
123
+ "engine.diagnose.wcag_rules_v0_1",
124
+ "engine.extract.evidence.json_pointer_v0_1",
125
+ "engine.extract.evidence.selector_v0_1",
126
+ "engine.generate.fix_guidance_v0_1"
127
+ ],
128
+ "inputs": [
129
+ "bundle:fixture:9b6d3c01",
130
+ "artifact:dom:index",
131
+ "artifact:dom:contact"
132
+ ],
133
+ "outputs": ["diagnosis:fixture-diag-001"],
134
+ "verified": true,
135
+ "timestamp": "2026-01-27T04:13:10.000Z"
136
+ }
137
+ }
138
+ }
139
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "mcp": {
3
+ "envelope": "mcp.envelope_v0_1",
4
+ "request_id": "req_fixture_diagnose_fail",
5
+ "tool": "a11y.diagnose",
6
+ "ok": false
7
+ },
8
+ "error": {
9
+ "code": "PROVENANCE_VERIFICATION_FAILED",
10
+ "message": "Evidence digest mismatch for artifact:dom:index. Expected sha256:a1b2c3..., got sha256:ffffff...",
11
+ "fix": "Re-run a11y.evidence to recapture evidence, or disable verify_provenance for local debugging."
12
+ }
13
+ }
@@ -0,0 +1,88 @@
1
+ {
2
+ "mcp": {
3
+ "envelope": "mcp.envelope_v0_1",
4
+ "request_id": "req_fixture_evidence_001",
5
+ "tool": "a11y.evidence",
6
+ "ok": true
7
+ },
8
+ "result": {
9
+ "bundle": {
10
+ "bundle_id": "bundle:fixture:9b6d3c01",
11
+ "labels": ["a11y", "baseline", "wcag-2.2-aa"],
12
+ "artifacts": [
13
+ {
14
+ "artifact_id": "artifact:html:index",
15
+ "media_type": "text/html",
16
+ "locator": { "kind": "file", "path": "html/index.html" },
17
+ "size_bytes": 245,
18
+ "digest": {
19
+ "alg": "sha256",
20
+ "hex": "a1b2c3d4e5f6789012345678901234567890123456789012345678901234abcd"
21
+ },
22
+ "labels": ["source", "html", "a11y", "baseline", "wcag-2.2-aa"]
23
+ },
24
+ {
25
+ "artifact_id": "artifact:dom:index",
26
+ "media_type": "application/json",
27
+ "locator": { "kind": "derived", "from": "artifact:html:index" },
28
+ "size_bytes": 1024,
29
+ "digest": {
30
+ "alg": "sha256",
31
+ "hex": "b2c3d4e5f67890123456789012345678901234567890123456789012345abcde"
32
+ },
33
+ "labels": ["derived", "dom-snapshot", "a11y", "baseline", "wcag-2.2-aa"]
34
+ },
35
+ {
36
+ "artifact_id": "artifact:html:contact",
37
+ "media_type": "text/html",
38
+ "locator": { "kind": "file", "path": "html/contact.html" },
39
+ "size_bytes": 312,
40
+ "digest": {
41
+ "alg": "sha256",
42
+ "hex": "c3d4e5f678901234567890123456789012345678901234567890123456abcdef"
43
+ },
44
+ "labels": ["source", "html", "a11y", "baseline", "wcag-2.2-aa"]
45
+ },
46
+ {
47
+ "artifact_id": "artifact:dom:contact",
48
+ "media_type": "application/json",
49
+ "locator": { "kind": "derived", "from": "artifact:html:contact" },
50
+ "size_bytes": 1156,
51
+ "digest": {
52
+ "alg": "sha256",
53
+ "hex": "d4e5f6789012345678901234567890123456789012345678901234567abcdef0"
54
+ },
55
+ "labels": ["derived", "dom-snapshot", "a11y", "baseline", "wcag-2.2-aa"]
56
+ }
57
+ ],
58
+ "provenance": {
59
+ "record_id": "prov:record:fixture-001",
60
+ "methods": [
61
+ "engine.capture.html_canonicalize_v0_1",
62
+ "engine.capture.dom_snapshot_v0_1",
63
+ "adapter.integrity.sha256_v0_1",
64
+ "adapter.provenance.record_v0_1"
65
+ ],
66
+ "inputs": ["html/index.html", "html/contact.html"],
67
+ "outputs": [
68
+ "artifact:html:index",
69
+ "artifact:dom:index",
70
+ "artifact:html:contact",
71
+ "artifact:dom:contact"
72
+ ],
73
+ "verified": false,
74
+ "timestamp": "2026-01-27T04:12:00.000Z",
75
+ "agent": {
76
+ "name": "a11y-mcp-tools",
77
+ "version": "0.2.0"
78
+ }
79
+ },
80
+ "environment": {
81
+ "os": { "platform": "win32", "arch": "x64" },
82
+ "node": "v20.10.0",
83
+ "tool_versions": { "a11y-mcp-tools": "0.2.0" }
84
+ },
85
+ "created_at": "2026-01-27T04:12:00.000Z"
86
+ }
87
+ }
88
+ }