test_accessibility
Test website accessibility against WCAG standards using Playwright and axe-core to identify compliance issues and generate detailed reports.
Instructions
Run accessibility tests on a website using Playwright and axe-core against WCAG standards
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | The URL of the website to test for accessibility | |
| wcagLevel | No | WCAG compliance level to test against | AA |
| wcagVersion | No | WCAG version to test against | 2.1 |
| browser | No | Browser engine to use for testing | chromium |
| includeScreenshot | No | Whether to capture a screenshot of the page |
Implementation Reference
- src/server/mcpServer.ts:139-218 (handler)Main MCP handler for 'test_accessibility' tool: validates URL, initializes tester, runs test, saves results to files, formats summary response.private async handleAccessibilityTest(request: MCPTestRequest): Promise<CallToolResult> { console.log(`Starting accessibility test for: ${request.url}`); // Validate URL try { new URL(request.url); } catch { throw new Error('Invalid URL provided'); } // Initialize browser await this.tester.initialize(); try { // Run the test const results = await this.tester.run(request.url, request.wcagLevel, request.criticality); const testResult: AccessibilityTestResult = { id: uuidv4(), timestamp: new Date(), url: request.url, options: { url: request.url, wcagLevel: request.wcagLevel, criticality: request.criticality, browser: request.browser || 'chromium', }, axeResults: results, summary: { violations: results.violations.length, passes: results.passes.length, incomplete: results.incomplete.length, inapplicable: results.inapplicable.length, }, }; // Save results to file const filePath = await this.fileManager.saveTestResult(testResult); // Also save raw JSON results for potential programmatic access const rawFilePath = await this.fileManager.saveRawResults(testResult); const response: MCPTestResponse = { success: testResult.error === undefined, testId: testResult.id, filePath, summary: { violations: testResult.summary.violations, passes: testResult.summary.passes, url: testResult.url, timestamp: testResult.timestamp.toISOString() }, error: testResult.error }; const summary = testResult.error ? `β Test failed: ${testResult.error}` : `β Test completed successfully!\n\n` + `π **Summary for ${testResult.url}:**\n` + `- Violations: ${testResult.summary.violations}\n` + `- Passes: ${testResult.summary.passes}\n` + `- Incomplete: ${testResult.summary.incomplete}\n` + `- Inapplicable: ${testResult.summary.inapplicable}\n\n` + `π Results saved to: ${path.basename(filePath)}\n` + `π Raw data: ${path.basename(rawFilePath)}`; return { content: [ { type: 'text', text: summary } ] }; } finally { // Clean up browser await this.tester.cleanup(); } }
- src/server/mcpServer.ts:43-80 (registration)Registration of 'test_accessibility' tool in ListTools response, defining name, description, and detailed inputSchema (url, wcagLevel, wcagVersion, browser, includeScreenshot).{ name: 'test_accessibility', description: 'Run accessibility tests on a website using Playwright and axe-core against WCAG standards', inputSchema: { type: 'object', properties: { url: { type: 'string', description: 'The URL of the website to test for accessibility', format: 'uri' }, wcagLevel: { type: 'string', enum: ['A', 'AA', 'AAA'], description: 'WCAG compliance level to test against', default: 'AA' }, wcagVersion: { type: 'string', enum: ['2.1', '2.2'], description: 'WCAG version to test against', default: '2.1' }, browser: { type: 'string', enum: ['chromium', 'firefox', 'webkit'], description: 'Browser engine to use for testing', default: 'chromium' }, includeScreenshot: { type: 'boolean', description: 'Whether to capture a screenshot of the page', default: false } }, required: ['url'] } },
- src/server/mcpServer.ts:46-79 (schema)JSON input schema for the tool defining properties, types, enums, descriptions, and requirements.inputSchema: { type: 'object', properties: { url: { type: 'string', description: 'The URL of the website to test for accessibility', format: 'uri' }, wcagLevel: { type: 'string', enum: ['A', 'AA', 'AAA'], description: 'WCAG compliance level to test against', default: 'AA' }, wcagVersion: { type: 'string', enum: ['2.1', '2.2'], description: 'WCAG version to test against', default: '2.1' }, browser: { type: 'string', enum: ['chromium', 'firefox', 'webkit'], description: 'Browser engine to use for testing', default: 'chromium' }, includeScreenshot: { type: 'boolean', description: 'Whether to capture a screenshot of the page', default: false } }, required: ['url'] }
- src/accessibility/tester.ts:20-54 (helper)Core testing logic in AccessibilityTester.run(): launches Playwright browser, navigates to URL, runs axe-core with WCAG tags, filters by criticality, saves screenshot.public async run(url: string, wcagLevel?: string, criticality?: string[]): Promise<AxeResults> { if (!this.browser) { await this.initialize(); } const context = await this.browser!.newContext(); const page = await context.newPage(); try { await page.goto(url); const axeBuilder = new AxeBuilder({ page }); if (wcagLevel) { axeBuilder.withTags([wcagLevel]); } let results = await axeBuilder.analyze(); // Filter violations by criticality if specified if (criticality && criticality.length > 0) { results.violations = results.violations.filter(violation => violation.impact && criticality.includes(violation.impact) ); } const screenshotPath = await this.saveScreenshot(page); console.log(`Screenshot saved to ${screenshotPath}`); return results; } finally { await page.close(); await context.close(); } }
- src/types/index.ts:47-54 (schema)TypeScript interface MCPTestRequest defining typed input parameters for the handler.export interface MCPTestRequest { url: string; wcagLevel?: string; criticality?: string[]; wcagVersion?: '2.1' | '2.2'; browser?: 'chromium' | 'firefox' | 'webkit'; includeScreenshot?: boolean; }