Skip to main content
Glama

runAccessibilityAudit

Conduct an accessibility audit on the current webpage to evaluate compliance with accessibility standards and identify potential issues for improvement.

Instructions

Run an accessibility audit on the current page

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • MCP tool registration for 'runAccessibilityAudit'. This registers the tool with the MCP server and defines its handler which proxies the request to the browser-tools-server /accessibility-audit endpoint.
    server.tool( "runAccessibilityAudit", "Run an accessibility audit on the current page", {}, async () => { return await withServerConnection(async () => { try { // Simplified approach - let the browser connector handle the current tab and URL console.log( `Sending POST request to http://${discoveredHost}:${discoveredPort}/accessibility-audit` ); const response = await fetch( `http://${discoveredHost}:${discoveredPort}/accessibility-audit`, { method: "POST", headers: { "Content-Type": "application/json", Accept: "application/json", }, body: JSON.stringify({ category: AuditCategory.ACCESSIBILITY, source: "mcp_tool", timestamp: Date.now(), }), } ); // Log the response status console.log(`Accessibility audit response status: ${response.status}`); if (!response.ok) { const errorText = await response.text(); console.error(`Accessibility audit error: ${errorText}`); throw new Error(`Server returned ${response.status}: ${errorText}`); } const json = await response.json(); // flatten it by merging metadata with the report contents if (json.report) { const { metadata, report } = json; const flattened = { ...metadata, ...report, }; return { content: [ { type: "text", text: JSON.stringify(flattened, null, 2), }, ], }; } else { // Return as-is if it's not in the new format return { content: [ { type: "text", text: JSON.stringify(json, null, 2), }, ], }; } } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); console.error("Error in accessibility audit:", errorMessage); return { content: [ { type: "text", text: `Failed to run accessibility audit: ${errorMessage}`, }, ], }; } }); } );
  • Core handler function that executes the accessibility audit using Lighthouse and processes the raw results into an AI-optimized report format.
    export async function runAccessibilityAudit( url: string ): Promise<AIOptimizedAccessibilityReport> { try { const lhr = await runLighthouseAudit(url, [AuditCategory.ACCESSIBILITY]); return extractAIOptimizedData(lhr, url); } catch (error) { throw new Error( `Accessibility audit failed: ${ error instanceof Error ? error.message : String(error) }` ); } }
  • Endpoint setup for /accessibility-audit in the browser server. Registers the POST handler that gets the current URL and calls the lighthouse runAccessibilityAudit function.
    private setupAccessibilityAudit() { this.setupAuditEndpoint( AuditCategory.ACCESSIBILITY, "/accessibility-audit", runAccessibilityAudit ); } // Sets up the performance audit endpoint private setupPerformanceAudit() { this.setupAuditEndpoint( AuditCategory.PERFORMANCE, "/performance-audit", runPerformanceAudit ); } // Set up SEO audit endpoint private setupSEOAudit() { this.setupAuditEndpoint(AuditCategory.SEO, "/seo-audit", runSEOAudit); } // Add a setup method for Best Practices audit private setupBestPracticesAudit() { this.setupAuditEndpoint( AuditCategory.BEST_PRACTICES, "/best-practices-audit", runBestPracticesAudit ); } /** * Generic method to set up an audit endpoint * @param auditType The type of audit (accessibility, performance, SEO) * @param endpoint The endpoint path * @param auditFunction The audit function to call */ private setupAuditEndpoint( auditType: string, endpoint: string, auditFunction: (url: string) => Promise<LighthouseReport> ) { // Add server identity validation endpoint this.app.get("/.identity", (req, res) => { res.json({ signature: "mcp-browser-connector-24x7", version: "1.2.0", }); }); this.app.post(endpoint, async (req: any, res: any) => { try { console.log(`${auditType} audit request received`); // Get URL using our helper method const url = await this.getUrlForAudit(); if (!url) { console.log(`No URL available for ${auditType} audit`); return res.status(400).json({ error: `URL is required for ${auditType} audit. Make sure you navigate to a page in the browser first, and the browser-tool extension tab is open.`, }); } // If we're using the stored URL (not from request body), log it now if (!req.body?.url && url === currentUrl) { console.log(`Using stored URL for ${auditType} audit:`, url); } // Check if we're using the default URL if (url === "about:blank") { console.log(`Cannot run ${auditType} audit on about:blank`); return res.status(400).json({ error: `Cannot run ${auditType} audit on about:blank`, }); } console.log(`Preparing to run ${auditType} audit for: ${url}`); // Run the audit using the provided function try { const result = await auditFunction(url); console.log(`${auditType} audit completed successfully`); // Return the results res.json(result); } catch (auditError) { console.error(`${auditType} audit failed:`, auditError); const errorMessage = auditError instanceof Error ? auditError.message : String(auditError); res.status(500).json({ error: `Failed to run ${auditType} audit: ${errorMessage}`, }); } } catch (error) { console.error(`Error in ${auditType} audit endpoint:`, error); const errorMessage = error instanceof Error ? error.message : String(error); res.status(500).json({ error: `Error in ${auditType} audit endpoint: ${errorMessage}`, }); } }); }
  • Type definitions for the AI-optimized accessibility report schema, including report content, issues, and elements.
    export interface AccessibilityReportContent { score: number; // Overall score (0-100) audit_counts: { // Counts of different audit types failed: number; passed: number; manual: number; informative: number; not_applicable: number; }; issues: AIAccessibilityIssue[]; categories: { [category: string]: { score: number; issues_count: number; }; }; critical_elements: AIAccessibilityElement[]; prioritized_recommendations?: string[]; // Ordered list of recommendations } /** * Full accessibility report implementing the base LighthouseReport interface */ export type AIOptimizedAccessibilityReport = LighthouseReport<AccessibilityReportContent>; /** * AI-optimized accessibility issue */ interface AIAccessibilityIssue { id: string; // e.g., "color-contrast" title: string; // e.g., "Color contrast is sufficient" impact: "critical" | "serious" | "moderate" | "minor"; category: string; // e.g., "contrast", "aria", "forms", "keyboard" elements?: AIAccessibilityElement[]; // Elements with issues score: number | null; // 0-1 or null } /** * Accessibility element with issues */ interface AIAccessibilityElement { selector: string; // CSS selector snippet?: string; // HTML snippet label?: string; // Element label issue_description?: string; // Description of the issue value?: string | number; // Current value (e.g., contrast ratio) }
  • Helper function that launches a headless browser instance and runs the Lighthouse audit for specified categories.
    export async function runLighthouseAudit( url: string, categories: string[] ): Promise<LighthouseResult> { console.log(`Starting Lighthouse ${categories.join(", ")} audit for: ${url}`); if (!url || url === "about:blank") { console.error("Invalid URL for Lighthouse audit"); throw new Error( "Cannot run audit on an empty page or about:blank. Please navigate to a valid URL first." ); } try { // Always use a dedicated headless browser for audits console.log("Using dedicated headless browser for audit"); // Determine if this is a performance audit - we need to load all resources for performance audits const isPerformanceAudit = categories.includes(AuditCategory.PERFORMANCE); // For performance audits, we want to load all resources // For accessibility or other audits, we can block non-essential resources try { const { port } = await connectToHeadlessBrowser(url, { blockResources: !isPerformanceAudit, }); console.log(`Connected to browser on port: ${port}`); // Create Lighthouse config const { flags, config } = createLighthouseConfig(categories); flags.port = port; console.log( `Running Lighthouse with categories: ${categories.join(", ")}` ); const runnerResult = await lighthouse(url, flags as Flags, config); console.log("Lighthouse scan completed"); if (!runnerResult?.lhr) { console.error("Lighthouse audit failed to produce results"); throw new Error("Lighthouse audit failed to produce results"); } // Schedule browser cleanup after a delay to allow for subsequent audits scheduleBrowserCleanup(); // Return the result const result = runnerResult.lhr; return result; } catch (browserError) { // Check if the error is related to Chrome/Edge not being available const errorMessage = browserError instanceof Error ? browserError.message : String(browserError); if ( errorMessage.includes("Chrome could not be found") || errorMessage.includes("Failed to launch browser") || errorMessage.includes("spawn ENOENT") ) { throw new Error( "Chrome or Edge browser could not be found. Please ensure that Chrome or Edge is installed on your system to run audits." ); } // Re-throw other errors throw browserError; } } catch (error) { console.error("Lighthouse audit failed:", error); // Schedule browser cleanup even if the audit fails scheduleBrowserCleanup(); throw new Error( `Lighthouse audit failed: ${ error instanceof Error ? error.message : String(error) }` ); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Sugatraj/Cursor-Browser-Tools-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server