ux-audit-mcp
v0.4.0
Published
UX audit MCP server: flow-based Playwright capture, DOM-grounded findings, skill packs, deterministic validation, annotation, and interactive viewer
Maintainers
Readme
ux-audit-mcp
MCP server that powers UX audits of UI screenshots — subscription-only, no API key anywhere.
The brain and the hands are separated: Claude (your subscription — Claude Code / Cowork / Desktop) is the brain that reads the screenshot and performs every analysis; this server is the hands — capture, skill-pack assembly, deterministic validation, annotation, viewer, storage. The server makes zero AI calls.
┌─────────────────────────────┐ ┌──────────────────────────────────┐
│ BRAIN: Claude (your │ │ HANDS: ux-audit-mcp server │
│ subscription) │ MCP │ (Node/TS, stdio — NO AI calls) │
│ • reads the screenshot │ ─────→ │ capture_url (Playwright) │
│ • runs each skill pack │ │ get_skill_pack (prompt asm) │
│ as an analysis pass │ │ validate_findings (det. gate) │
│ • produces findings JSON │ │ annotate_image (Sharp) │
│ • calls tools to draw/save │ │ build_viewer · save_audit · … │
└─────────────────────────────┘ └──────────────────────────────────┘Setup
npm install && npx playwright install chromium
npm run build
claude mcp add ux-audit -- node /absolute/path/to/ux-audit-mcp/dist/index.jsNo environment variables. No API key.
How an audit runs
- "Audit this screenshot" (attach image or give a URL) in Claude Code/Cowork.
- Claude follows skills/_orchestrator/SKILL.md — the scripted loop, never improvised:
capture_urlif a URL was given (desktop 1440×900 / mobile 390×844, SSRF-guarded, CAPTCHA-walls audited as-is)get_skill_pack× 7 groups — each pack = methodology + group docs + group rules + output spec, hard-capped at ~10k tokens (rules compress to id+title when over)- Claude performs the vision analysis per pack (parallel subagents in headless mode, sequential in chat)
validate_findings— deterministic gate replacing API schema forcing: structure, bbox sanity, fp-gate, confidence ≥0.6, IoU>0.5 dedupe, praise cap 3, reading-order renumber. Rejected findings bounce back with reasons (max 2 fix rounds)save_audit→annotate_image→build_viewer
Headless (still subscription)
./scripts/run-audit.sh /path/to/screen.png
./scripts/run-audit.sh https://example.com mobileInvokes claude -p (Pro/Max auth). The orchestrator spawns the 7 packs as parallel subagents — fresh isolated context per pack — recovering API-style context isolation + parallelism without a key. The gauntlet runs in this mode.
Tools (13)
| Tool | Role |
|---|---|
| capture_url | url + viewport → full-page PNG. SSRF blocklist incl. DNS-resolution check |
| get_skill_pack | group → assembled analysis prompt (methodology + docs + rules + output spec, ~10k-token cap) |
| validate_findings | findings[] + image dims → accepted[] + rejected[{reasons}] |
| save_audit | image + validated findings → audits// (original.png, findings.json, meta.json) |
| annotate_image | audit_id → annotated.png; or standalone image+findings from any source → full artifact set |
| build_viewer | audit_id → self-contained viewer.html |
| get_findings / explain_finding / list_audits | retrieval |
| list_skills / get_skill / add_skill / update_skill | skills CRUD, hot-reloaded (ref: <group>/<doc>) |
Finding schema (validation-enforced)
Issues require: severity, why (constructive, names the principle), how_it_happens (likely mechanism), evidence, user_impact → business_impact, recommendation, confidence ≥0.6, and the 4-question fp_check (blocks_goal must be true; standard_pattern/suggests_clutter/plausibly_intentional must be false). Praise (type: "praise"): no severity, no fp_check, capped 3/screen, green render, excluded from counts.
Skills — 7 groups, 27 docs
| Group | Docs | |---|---| | hierarchy | visual-hierarchy · layout-spacing · gestalt-perception (names the principle, GEST rules) · aesthetic-minimalism | | copy | ux-copy-microcopy · cta-wording · jargon-realworld-match · i18n-content | | forms | forms-inputs · error-validation · autofill-formats | | navigation | navigation-ia · recognition-vs-recall · search-filtering | | feedback | system-status · empty-states · loading-perception · notifications-alerts · help-docs | | layout | typography (bencium craft rules) · tables-data-display · modals-overlays · consistency-components | | a11y-visual | accessibility-wcag · mobile-touch · cognitive-load · trust-security-cues |
_methodology.md prepends every pack: ground-truth rule, fp-gate, causal chain (+how_it_happens), severity bands with anti-compression, praise discipline. 245 rules in rules/ with provenance tags (seed:gestalt, seed:shneiderman, seed:jakobs-law, seed:millers-law, seed:bastien-scapin, seed:gerhardt-powals, seed:vercel-wig, seed:bencium-typography).
Phase 2 (deferred): focus-keyboard, responsive-breakpoints, user-control-freedom, flow-patterns, consistency-cross-screen, persuasion/trust (Fogg/Cialdini), glossary.html, DOM grounding.
Viewer
Single self-contained viewer.html (zero deps, offline): image + overlay boxes left, Acrobat-style comment sidebar right — per card: number, severity chip (or green "working well"), title, why → how it happens → impact chain → fix, rule id, confidence. Click box ↔ card sync, severity/category/praise filter pills, ↑/↓ keys, copy-as-markdown.
Layout
ux-audit-mcp/
├── src/ # server + tools (no AI client code)
├── skills/ # 7 groups + _methodology.md + _orchestrator/SKILL.md
├── rules/ # 245 yml rules
├── scripts/run-audit.sh # headless: claude -p, parallel subagents
└── audits/<id>/ # original.png · annotated.png · findings.json · viewer.html · meta.jsonmeta.json logs skill groups used, validation bounce count (quality signal), source url/viewport. Cost: n/a — subscription.
Dev
npm run dev # tsc --watch
npm run smoke # 38 checks: validation gate, artifact chain, packs under cap, SSRF