accessibility_audit
Audit the current screen for accessibility violations, including missing labels, small tap targets, and images without alt text, and receive a detailed report.
Instructions
Verifie l'accessibilite de l'ecran actuel : labels manquants, tap targets trop petits, images sans alt text. Retourne un rapport de violations.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- src/tools/accessibility-audit.ts:86-149 (handler)The tool handler function that performs the accessibility audit. It resolves the device, gets the UI tree (iOS via WDA or Android via adb), runs audit checks on all elements, and returns a formatted report of violations.
export function registerAccessibilityAudit(server: McpServer): void { server.tool( "accessibility_audit", "Verifie l'accessibilite de l'ecran actuel : labels manquants, tap targets trop petits, images sans alt text. Retourne un rapport de violations.", {}, async () => { const result = await resolveDevice(); if ("error" in result) return { content: [{ type: "text", text: result.error }], isError: true }; const dev = result.device; try { let elements: ParsedElement[]; if (dev.platform === "ios") { const wda = await ensureWdaRunning(dev); if (!wda.ready) return { content: [{ type: "text", text: wda.message ?? "WDA indisponible." }], isError: true }; elements = await iosGetUiTree(); } else { elements = await androidGetUiTree(); } if (elements.length === 0) { return { content: [{ type: "text", text: `Accessibility Audit — ${dev.name} (${dev.platform})\n\nWARNING — Aucun élément détecté. L'écran semble vide ou en transition. Réessaie après le chargement.` }], isError: true, }; } const violations = auditElements(elements, dev.platform); const errors = violations.filter((v) => v.severity === "error"); const warnings = violations.filter((v) => v.severity === "warning"); const lines: string[] = [ `Accessibility Audit — ${dev.name} (${dev.platform})`, `Éléments analysés : ${elements.length}`, "", ]; if (violations.length === 0) { lines.push("PASS — Aucune violation détectée."); } else { lines.push(`VIOLATIONS (${violations.length}) :`); lines.push(""); for (const v of violations) { const icon = v.severity === "error" ? "[ERROR]" : "[WARNING]"; lines.push(`${icon} ${v.check} : ${v.message} — ${v.element}`); } lines.push(""); lines.push(`Resume : ${errors.length} erreur(s), ${warnings.length} avertissement(s), ${elements.length - violations.length} element(s) OK`); } logAction("accessibility_audit", `${violations.length} violation(s) trouvée(s)`, errors.length > 0, dev.platform, dev.id, dev.name); return { content: [{ type: "text", text: lines.join("\n") }], isError: errors.length > 0, }; } catch (err) { const msg = err instanceof Error ? err.message : String(err); return { content: [{ type: "text", text: `Erreur accessibility_audit: ${msg}` }], isError: true }; } } ); - src/tools/accessibility-audit.ts:36-84 (handler)Core audit logic: checks interactive elements for missing labels (A), tap targets too small (B), and images without alt text (C). Returns a list of Violations with severity grading.
function auditElements(elements: ParsedElement[], platform: "ios" | "android"): Violation[] { const violations: Violation[] = []; const minTap = platform === "ios" ? IOS_MIN_TAP : ANDROID_MIN_TAP; for (const el of elements) { const displayText = el.label || el.name || el.value || ""; const pos = `(${el.x},${el.y} ${el.width}x${el.height})`; // Check A — Interactive elements without labels if (isInteractive(el.type, platform)) { if (!el.label && !el.name && !el.value) { violations.push({ severity: "error", check: "missing-label", message: `${el.type} sans texte accessible`, element: `${el.type} ${pos}`, position: pos, }); } // Check B — Tap target too small if (el.width < minTap || el.height < minTap) { const severity = el.width < minTap * 0.75 || el.height < minTap * 0.75 ? "error" : "warning"; violations.push({ severity, check: "tap-target-small", message: `${el.type} "${displayText}" trop petit : ${el.width}x${el.height} (min ${minTap}x${minTap})`, element: `${el.type} "${displayText}" ${pos}`, position: pos, }); } } // Check C — Images without alt text if (isImage(el.type, platform)) { if (!el.label && !el.name && !el.value) { violations.push({ severity: "warning", check: "image-no-alt", message: `Image sans texte alternatif`, element: `${el.type} ${pos}`, position: pos, }); } } } return violations; } - The Violation interface defining the structure of each audit finding with severity, check name, message, element description, and position.
interface Violation { severity: "error" | "warning"; check: string; message: string; element: string; position: string; } - Platform-specific sets for interactive element types and image types, plus minimum tap target sizes (44px for iOS, 48px for Android).
// Interactive element types per platform const IOS_INTERACTIVE = new Set(["Button", "TextField", "SecureTextField", "Switch", "Slider", "Stepper", "Link", "SearchField", "SegmentedControl"]); const ANDROID_INTERACTIVE = new Set(["Button", "EditText", "CheckBox", "RadioButton", "Switch", "SeekBar", "ImageButton", "ToggleButton", "FloatingActionButton"]); // Image types per platform const IOS_IMAGE = new Set(["Image"]); const ANDROID_IMAGE = new Set(["ImageView", "ImageButton"]); // Minimum tap target sizes const IOS_MIN_TAP = 44; const ANDROID_MIN_TAP = 48; - src/index.ts:22-70 (registration)Import and registration of the accessibility_audit tool on line 22 (import) and line 67 (registration call).
import { registerAccessibilityAudit } from "./tools/accessibility-audit.js"; import { registerTestReport } from "./tools/test-report.js"; import { registerVisualDiff } from "./tools/visual-diff.js"; import { registerMultiDevice } from "./tools/multi-device.js"; const server = new McpServer({ name: "phantom", version: "2.3.0", }); // Device management registerListDevices(server); registerSetDevice(server); registerPrepareDevice(server); // Observation registerScreenshot(server); registerGetUiTree(server); registerWaitForElement(server); registerScrollUntilVisible(server); // Assertions registerAssertVisible(server); registerAssertNotVisible(server); // Interaction registerTap(server); registerLongPress(server); registerTypeText(server); registerSwipe(server); registerDismissKeyboard(server); // Navigation registerDeepLink(server); // Device actions registerShake(server); registerRotate(server); registerVideoRecord(server); // App lifecycle registerLaunchApp(server); registerKillApp(server); // Tier 3 — Analysis & Automation registerAccessibilityAudit(server); registerTestReport(server); registerVisualDiff(server); registerMultiDevice(server);