ui-unslop-mcp
by fikrifirmanf
README.md
# ui-unslop-mcp
> Make AI-built interfaces look designed and pass accessibility: WCAG contrast (computed from Tailwind class pairs), a11y failures, design-token sprawl and the visual tells of generated UI, for any web stack.
[](https://www.npmjs.com/package/ui-unslop-mcp)
[](./LICENSE)
[](https://modelcontextprotocol.io)
An **agent skill** plus an **MCP server** in one package. The skill tells your coding agent what slop to avoid; the MCP tools then *deterministically verify* the result, so the agent can't just claim it's done.
Works with **Claude Code**, **Claude Desktop**, **Codex** and **Antigravity**.
## What it catches
| Rule | Severity | Catches |
| --- | --- | --- |
| `LOW_CONTRAST_TEXT` | ERROR | Text/background pair fails WCAG AA contrast. |
| `IMG_WITHOUT_ALT` | ERROR | Image without alt. Describe it, or use alt="" for purely decorative images. |
| `CLICKABLE_NON_INTERACTIVE` | ERROR | onClick on a non-interactive element: unreachable by keyboard and screen readers. Use <button> or <a href>. |
| `ICON_ONLY_CONTROL_UNLABELLED` | ERROR | Icon-only button/link has no accessible name. Add aria-label. |
| `FOCUS_INDICATOR_REMOVED` | ERROR | Focus outline removed without a replacement. Keep a visible focus-visible style (ring/outline) for keyboard users. |
| `ZOOM_DISABLED` | ERROR | Pinch-zoom disabled. Low-vision users need zoom; remove user-scalable=no / maximum-scale=1. |
| `POSITIVE_TABINDEX` | ERROR | Positive tabindex scrambles keyboard order. Use 0 or -1 and fix the DOM order instead. |
| `TINY_TEXT` | ERROR | Text below 12px is unreadable on most screens. Use 12px+ (14px+ for body copy). |
| `EMOJI_AS_ICON` | WARN | Emoji used as UI iconography reads as a generated template. Use the project's icon set (or nothing). |
| `GRADIENT_TEXT` | WARN | Gradient-filled headline text is the default AI landing-page look and often fails contrast. Use a solid token color. |
| `GLASSMORPHISM_CARD` | WARN | Frosted-glass card (bg-white/10 + backdrop-blur) is a generated-UI tell and hurts legibility. Use a solid surface token. |
| `TRANSITION_ALL` | WARN | transition-all animates layout properties and causes jank. Transition specific properties (colors, opacity, transform). |
| `FULL_VIEWPORT_HEIGHT` | WARN | 100vh overflows behind mobile browser toolbars. Use min-h-dvh / min-h-svh (100dvh). |
| `Z_INDEX_ARMS_RACE` | WARN | z-index in the hundreds/thousands signals a stacking-context fight. Define a small z-index scale. |
| `IMPORTANT_OVERRIDE` | WARN | !important override. Fix specificity or layer order (@layer) instead. |
| `ATTENTION_ANIMATION` | WARN | Bouncing/pinging attention animation on UI. Draw attention with hierarchy, and respect prefers-reduced-motion. |
| `PLACEHOLDER_AS_LABEL` | WARN | Input labelled only by its placeholder (disappears on typing, low contrast). Add a <label htmlFor> or aria-label. |
`LOW_CONTRAST_TEXT` resolves `text-*`/`bg-*` pairs in the same class string against the Tailwind v4 palette and computes the real WCAG ratio for light and `dark:` variants, suggesting the nearest passing shade. Translucent backgrounds are skipped (unknown backdrop); check those with `check_contrast`.
Rules marked **ERROR** make the audit return `status: "FAIL"`; **WARN** is reported but does not fail.
## Quick start
### 1. Add the MCP server
```bash
# Claude Code
claude mcp add ui-unslop -s user -- npx -y ui-unslop-mcp
# Codex
codex mcp add ui-unslop -- npx -y ui-unslop-mcp
```
**Claude Desktop** (`~/Library/Application Support/Claude/claude_desktop_config.json`) and **Antigravity** (`~/.gemini/config/mcp_config.json`):
```json
{
"mcpServers": {
"ui-unslop": {
"command": "npx",
"args": ["-y", "ui-unslop-mcp"]
}
}
}
```
Restart the app afterwards.
### 2. Install the bundled skill
```bash
npx -y ui-unslop-mcp install-skills # clients that are installed
npx -y ui-unslop-mcp install-skills --all # every location
```
| Client | Location |
| --- | --- |
| Claude Code | `~/.claude/skills/` |
| Codex | `~/.codex/skills/` |
| Antigravity | `~/.gemini/config/skills/` (and `~/.gemini/antigravity/skills/` if present) |
Claude Desktop has no skills folder, so it receives the rules through the MCP prompt and the `load_*_rules` tool.
## MCP surface
| Kind | Name | Purpose |
| --- | --- | --- |
| Prompt | `ui-unslop` | The full skill text, for GUI clients |
| Tool | `load_ui_unslop_rules` | Returns the full ui-unslop ruleset. Call before writing code if the ui-unslop skill is not already loaded. |
| Tool | `audit_ui_slop` | Deterministically scans markup and stylesheets for UI slop and accessibility failures: low-contrast Tailwind text/background pairs, images without alt, clickable divs, unlabelled icon buttons, removed focus rings, disabled zoom, positive tabindex, tiny text, emoji icons, gradient text, glassmorphism, transition-all, 100vh, z-index wars and placeholder-only labels. Accepts files or directories; with no files it audits the git working-tree changes. Suppress a verified false positive with a `unslop-ignore RULE_ID -- reason` comment on or above the line. |
| Tool | `check_contrast` | Computes WCAG 2.x contrast ratios. Colors may be #hex, rgb(), hsl(), oklch(), CSS names or Tailwind v4 palette names (slate-400, text-slate-400/80). Returns AA/AAA pass and, for Tailwind colors, the nearest passing shade. Use it before choosing text, border and focus colors. |
| Tool | `analyze_design_tokens` | Inventories hardcoded design values across stylesheets and markup: distinct colors, font sizes, radii, shadows, z-indexes, font families and off-grid spacing. Flags sprawl beyond a coherent system so you consolidate into tokens instead of inventing more one-offs. |
File paths resolve against the server's working directory and cannot escape it. Directories honour `.gitignore` and skip `node_modules`, build output and minified files.
## CLI and CI
The same audit runs without an agent. It exits `1` on any ERROR, so it works as a pre-commit hook or CI step:
```bash
npx -y ui-unslop-mcp audit # git working-tree changes
npx -y ui-unslop-mcp audit src app # files or directories
npx -y ui-unslop-mcp audit src --json # machine-readable
npx -y ui-unslop-mcp rules # list every rule
```
## Suppressing a false positive
The checks are regex and structure based: fast, offline and predictable, but heuristic. For a verified false positive, add a comment on the line or the line above, **with a reason**:
```js
// unslop-ignore LOW_CONTRAST_TEXT -- why this is safe here
```
Suppressions without a reason are reported as `SUPPRESSION_WITHOUT_REASON` errors, and every honoured suppression is listed in the audit output so reviewers can see it.
## How it works
1. The agent loads the skill and writes code under its constraints.
2. Before finishing, the skill requires the audit and verification tools.
3. On `FAIL`, the agent fixes every finding and re-runs until `PASS`. Missing toolchains are reported as `SKIPPED`, never as passing.
## The unslop family
- [`backend-unslop-mcp`](https://github.com/fikrifirmanf/backend-unslop-mcp)
- [`frontend-unslop-mcp`](https://github.com/fikrifirmanf/frontend-unslop-mcp)
- [`mobile-unslop-mcp`](https://github.com/fikrifirmanf/mobile-unslop-mcp)
- [`copy-unslop-mcp`](https://github.com/fikrifirmanf/copy-unslop-mcp)
- [`test-unslop-mcp`](https://github.com/fikrifirmanf/test-unslop-mcp)
All share the engine in [`unslop-core`](https://github.com/fikrifirmanf/unslop-core).
## Development
```bash
git clone https://github.com/fikrifirmanf/ui-unslop-mcp
cd ui-unslop-mcp && npm install
npm test # every rule is checked against its good/bad examples
node src/server.mjs # speaks MCP over stdio
```
## License
MIT © Fikri Firman Fadilah
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues