test_accessibility
Test website accessibility using Playwright and axe-core to identify WCAG compliance violations and generate detailed reports with remediation guidance.
Instructions
Run accessibility tests on a website using Playwright and axe-core against WCAG standards
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| browser | No | Browser engine to use for testing | chromium |
| includeScreenshot | No | Whether to capture a screenshot of the page | |
| 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 |
Implementation Reference
- src/server/mcpServer.ts:139-218 (handler)Main handler function for test_accessibility tool: validates input, runs AccessibilityTester, processes results, saves to file, and formats 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/accessibility/tester.ts:20-54 (helper)Core testing logic in AccessibilityTester.run(): launches browser, navigates to URL, runs axe-core analysis 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/server/mcpServer.ts:43-80 (registration)Registration of the 'test_accessibility' tool in the listTools handler, including name, description, and input schema.{ 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/types/index.ts:47-54 (schema)TypeScript interface MCPTestRequest defining the input structure for the test_accessibility tool.export interface MCPTestRequest { url: string; wcagLevel?: string; criticality?: string[]; wcagVersion?: '2.1' | '2.2'; browser?: 'chromium' | 'firefox' | 'webkit'; includeScreenshot?: boolean; }