@access-check/mcp-server 0.2.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.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,210 @@
1
+ #!/usr/bin/env node
2
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
5
+ import { z } from "zod";
6
+ const API_KEY = process.env.ACCESSCHECK_API_KEY;
7
+ const API_URL = process.env.ACCESSCHECK_API_URL || "https://api.accesscheck.dev/v1";
8
+ if (!API_KEY) {
9
+ console.error("Error: ACCESSCHECK_API_KEY environment variable is required.\n" +
10
+ "Get your API key at https://accesscheck.dev/pricing");
11
+ process.exit(1);
12
+ }
13
+ // --- API helper ---
14
+ async function apiRequest(method, path, body) {
15
+ const url = `${API_URL}${path}`;
16
+ console.error(`[accesscheck] ${method} ${url}`);
17
+ const res = await fetch(url, {
18
+ method,
19
+ headers: {
20
+ "Content-Type": "application/json",
21
+ "X-API-Key": API_KEY,
22
+ },
23
+ ...(body ? { body: JSON.stringify(body) } : {}),
24
+ });
25
+ if (!res.ok) {
26
+ const text = await res.text();
27
+ throw new Error(`API error ${res.status}: ${text}`);
28
+ }
29
+ return res.json();
30
+ }
31
+ // --- Polling helper ---
32
+ async function pollScan(scanId) {
33
+ const POLL_INTERVAL = 3000;
34
+ const MAX_ATTEMPTS = 60;
35
+ for (let i = 0; i < MAX_ATTEMPTS; i++) {
36
+ const result = (await apiRequest("GET", `/scans/${scanId}`));
37
+ if (result.status === "completed" || result.status === "failed") {
38
+ return result;
39
+ }
40
+ console.error(`[accesscheck] Scan ${scanId} status: ${result.status} (attempt ${i + 1}/${MAX_ATTEMPTS})`);
41
+ await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL));
42
+ }
43
+ // Timeout — return whatever we have
44
+ const finalResult = await apiRequest("GET", `/scans/${scanId}`);
45
+ return {
46
+ ...finalResult,
47
+ _warning: "Polling timed out after 3 minutes. Scan may still be running.",
48
+ };
49
+ }
50
+ // --- Input schemas ---
51
+ const ScanCookieInput = z.object({
52
+ name: z.string().min(1),
53
+ value: z.string(),
54
+ domain: z.string().min(1),
55
+ path: z.string().optional(),
56
+ });
57
+ const ScanAuthInput = z.object({
58
+ cookies: z.array(ScanCookieInput).max(20).optional(),
59
+ headers: z.record(z.string()).optional(),
60
+ });
61
+ const ScanUrlInput = z.object({
62
+ url: z.string().url("Must be a valid URL"),
63
+ auth: ScanAuthInput.optional(),
64
+ });
65
+ const GetScanInput = z.object({
66
+ id: z.string().min(1, "Scan ID is required"),
67
+ });
68
+ // --- MCP Server ---
69
+ const server = new Server({
70
+ name: "accesscheck",
71
+ version: "0.1.0",
72
+ }, {
73
+ capabilities: {
74
+ tools: {},
75
+ },
76
+ });
77
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
78
+ tools: [
79
+ {
80
+ name: "scan_url",
81
+ description: "Scan a URL for WCAG accessibility issues. Returns a compliance score (0-100), " +
82
+ "list of issues with severity, WCAG criteria, and fix suggestions. " +
83
+ "Scans typically take 15-45 seconds. Supports authenticated pages via optional cookies/headers.",
84
+ inputSchema: {
85
+ type: "object",
86
+ properties: {
87
+ url: {
88
+ type: "string",
89
+ description: "The URL to scan for accessibility issues",
90
+ },
91
+ auth: {
92
+ type: "object",
93
+ description: "Optional authentication for scanning protected pages. Cookies and headers are transient — never stored.",
94
+ properties: {
95
+ cookies: {
96
+ type: "array",
97
+ description: "Cookies to inject before page load (max 20)",
98
+ items: {
99
+ type: "object",
100
+ properties: {
101
+ name: { type: "string" },
102
+ value: { type: "string" },
103
+ domain: { type: "string" },
104
+ path: { type: "string" },
105
+ },
106
+ required: ["name", "value", "domain"],
107
+ },
108
+ },
109
+ headers: {
110
+ type: "object",
111
+ description: "HTTP headers to send with every request (e.g. Authorization)",
112
+ additionalProperties: { type: "string" },
113
+ },
114
+ },
115
+ },
116
+ },
117
+ required: ["url"],
118
+ },
119
+ },
120
+ {
121
+ name: "get_scan",
122
+ description: "Get results for a previously submitted scan by its ID. " +
123
+ "Use this to check on a scan that was started earlier.",
124
+ inputSchema: {
125
+ type: "object",
126
+ properties: {
127
+ id: {
128
+ type: "string",
129
+ description: "The scan ID returned from scan_url",
130
+ },
131
+ },
132
+ required: ["id"],
133
+ },
134
+ },
135
+ {
136
+ name: "list_rules",
137
+ description: "List all WCAG accessibility rules that AccessCheck scans for. " +
138
+ "Returns rule IDs, descriptions, WCAG criteria mappings, and impact levels.",
139
+ inputSchema: {
140
+ type: "object",
141
+ properties: {},
142
+ },
143
+ },
144
+ ],
145
+ }));
146
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
147
+ const { name, arguments: args } = request.params;
148
+ try {
149
+ switch (name) {
150
+ case "scan_url": {
151
+ const { url, auth } = ScanUrlInput.parse(args);
152
+ const scanResponse = (await apiRequest("POST", "/scans", { url, ...(auth ? { auth } : {}) }));
153
+ console.error(`[accesscheck] Scan created: ${scanResponse.id}`);
154
+ const result = await pollScan(scanResponse.id);
155
+ return {
156
+ content: [
157
+ { type: "text", text: JSON.stringify(result, null, 2) },
158
+ ],
159
+ };
160
+ }
161
+ case "get_scan": {
162
+ const { id } = GetScanInput.parse(args);
163
+ const result = await apiRequest("GET", `/scans/${id}`);
164
+ return {
165
+ content: [
166
+ { type: "text", text: JSON.stringify(result, null, 2) },
167
+ ],
168
+ };
169
+ }
170
+ case "list_rules": {
171
+ const result = await apiRequest("GET", "/rules");
172
+ return {
173
+ content: [
174
+ { type: "text", text: JSON.stringify(result, null, 2) },
175
+ ],
176
+ };
177
+ }
178
+ default:
179
+ return {
180
+ content: [
181
+ { type: "text", text: `Unknown tool: ${name}` },
182
+ ],
183
+ isError: true,
184
+ };
185
+ }
186
+ }
187
+ catch (error) {
188
+ const message = error instanceof z.ZodError
189
+ ? `Validation error: ${error.errors.map((e) => e.message).join(", ")}`
190
+ : error instanceof Error
191
+ ? error.message
192
+ : String(error);
193
+ console.error(`[accesscheck] Error in ${name}: ${message}`);
194
+ return {
195
+ content: [{ type: "text", text: message }],
196
+ isError: true,
197
+ };
198
+ }
199
+ });
200
+ // --- Start ---
201
+ async function main() {
202
+ const transport = new StdioServerTransport();
203
+ await server.connect(transport);
204
+ console.error("[accesscheck] MCP server running on stdio");
205
+ }
206
+ main().catch((error) => {
207
+ console.error("[accesscheck] Fatal error:", error);
208
+ process.exit(1);
209
+ });
210
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@access-check/mcp-server",
3
+ "version": "0.2.0",
4
+ "description": "MCP server for AccessCheck WCAG/ADA compliance scanning",
5
+ "type": "module",
6
+ "bin": {
7
+ "accesscheck-mcp": "./dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "dev": "tsx src/index.ts"
15
+ },
16
+ "keywords": [
17
+ "mcp",
18
+ "accessibility",
19
+ "wcag",
20
+ "ada",
21
+ "a11y",
22
+ "compliance"
23
+ ],
24
+ "author": "k-kruusi",
25
+ "license": "MIT",
26
+ "dependencies": {
27
+ "@modelcontextprotocol/sdk": "^1.6.1",
28
+ "zod": "^3.24.2"
29
+ },
30
+ "devDependencies": {
31
+ "@types/node": "^22.13.4",
32
+ "tsx": "^4.19.3",
33
+ "typescript": "^5.7.3"
34
+ }
35
+ }