uxlint
OfficialThis server audits websites for UX/design issues and supports an agent loop of fixing and re-checking findings.
audit_url: Run a full UX audit of a site (contrast, tap targets, type scale, colour discipline, copy clarity, scan patterns, interaction states, crawl routes, optional AI judge, declared tests). Returns graded verdict, findings with rule names, selectors, source hints, concrete fixes, and screenshot URLs.
get_report: Read an existing report by URL or ID — useful for timed-out runs, dashboard-started audits, or recovering a lost audit_url result.
get_shot: Fetch a finding's annotated screenshot (boxed element) using your login, returned inline and written to a local file.
ux_guidance: Read project design memory (uxlint.design.json) and best-practice UI guidance before building, covering layout, forms, lists, navigation, components, performance, accessibility, and content.
verify_fix: Re-check one rule on one page after an edit — returns passed/failed/not_evaluated/inconclusive, plus other deterministic findings on that page as a regression guard. Passing is supported for page-title-missing, html-lang-missing, and horizontal-overflow.
Auth/setup support: The tools guide setup when no uxlint.toml exists, handle login walls, and keep credentials local via project personas.
uxlint
Audit any website's UX the way a design-literate reviewer would: contrast, tap targets, type scale, colour discipline, scan patterns, landmarks. Every finding comes with a prescriptive fix an agent (or a human) can apply directly. It's designed to sit in a coding agent's loop (MCP) and be iterated against until green.

A real run, start to finish: audit_url → Grade B, a 2.39:1 contrast error and three CTAs in
three different accent hues → the fix → verify_fix → Grade A. Every number in it came back
from the tools; only the waiting was cut.
This is the CLI: a small, single static Rust binary. It drives a Chrome/Chromium you already have installed over the DevTools protocol (no Node, no Playwright, no headless-browser download), captures what a page looks and reads like, and sends that to uxlint's hosted server, which does the actual grading. The rules engine, the calibrated thresholds, and the LLM judge all live server-side, so the client never needs updating when a rule changes.
┌──────────────────────────┐ POST /v1/audit {snapshots} ┌──────────────────────────┐
│ uxlint (this binary) │ ───────────────────────────────────────▶ │ uxlint-server (hosted) │
│ drives YOUR Chrome (CDP) │ ◀─────────────────────────────────────── │ rules engine + LLM judge │
└──────────────────────────┘ report {findings + fixes} └──────────────────────────┘Install
curl -fsSL https://uxlint.net/install.sh | sh # detects OS/arch, verifies checksumOr with mise — its github backend pulls the matching build from GitHub
Releases, verifies it, and updates on mise up:
mise use -g "github:uxlint-net/uxlint-cli[rename_exe=uxlint]@latest"or pin it in a project's mise.toml:
[tools]
"github:uxlint-net/uxlint-cli" = { version = "latest", rename_exe = "uxlint" }Or build from source (needs a recent stable Rust toolchain and a Chrome/Chromium on PATH):
git clone https://github.com/uxlint-net/uxlint-cli && cd uxlint-cli
cargo build --release
./target/release/uxlint --versionRelated MCP server: mcp-a11y-service
Quickstart
uxlint auth login # opens your browser, saves a token
uxlint audit --base https://your-site.com --routes /,/pricingFirst time auditing your own project? uxlint init picks (or creates) a site to attach reports
to and writes a uxlint.toml so every future audit in this directory just works:
uxlint init
uxlint audit --base http://localhost:5173 --routes /,/pricingExit code 1 on findings above the configured severity → drop it straight into CI (see
.github/workflows/ for a template, or the uxlint-net/uxlint-action GitHub Action).
Hiding elements from an audit (uxlint-hide)
Some on-page chrome isn't product UI and shouldn't be judged: a dev/staging environment banner, a
"DEV" marker, a debug toolbar, a Storybook/preview affordance. Add the class uxlint-hide to any
such element and the audit removes it — it's display:none from first paint, so it never appears in a
screenshot and is invisible to the collector (it seeds no findings):
<div class="env-banner uxlint-hide">STAGING</div>The class is inert on your real site — it does nothing unless the audit is running, because the
stylesheet that hides it (.uxlint-hide { display: none !important; }) is injected only by uxlint's
browser, before the page's own scripts run. Style your element however you like the rest of the time.
It applies in every capture path — the crawl, goal-walk tests, and fix previews.
Does it change anything? (--allow-mutation)
Interaction audits navigate, read, and click candidate menu, disclosure, and dialog controls. Discovery skips controls whose accessible name contains a recognised action verb: delete, remove, accept, leave, revoke, cancel, transfer, pay, publish, submit, add, create, save, and their relatives, matched as whole words anywhere in the label. A label cannot prove what its click handler does, so run interaction audits against an environment you control with disposable data.
Two probes do write, and both need --allow-mutation on top of --states:
the action-feedback probe clicks a constructive action (Add / Create / Save) to check the page says something happened;
the destructive probe clicks Delete / Remove and clicks through the confirm dialog, to check the contract that a destructive action either confirms first or offers undo.
They power action-no-feedback, destructive-no-confirm and undo-missing, and those three rules
stay quiet without the flag. Throwaway environments only. Being signed in as a user who is allowed
to delete a row is not the same as having asked us to, and this flag is where you say so.
uxlint mcp never sets it, and cannot be asked to.
The other way an audit writes is one you wrote yourself: a declared [[tests]] walk signs in as a
persona and exercises real flows, which is what a test does.
MCP (use it from a coding agent)
Claude Code, one command:
/plugin marketplace add uxlint-net/uxlint-cli
/plugin install uxlint@uxlintThat installs the uxlint MCP server and, if the CLI isn't already on your PATH, fetches the matching
version once with the same checksum-verifying installer as above — so /plugin update updates the CLI
underneath it too. No Node needed: it downloads one static binary (verified against a published
checksum) and drives the Chrome you already have.
Any other agent — one line (the npm package fetches the binary for your platform, verifies the
checksum published beside it, and hands over). This is the only route that needs Node 18+, for
npx itself; if you'd rather not, install the binary with the line at the top and register that:
claude mcp add uxlint -- npx -y @uxlint-net/uxlint mcpOr, for a client that reads a JSON config:
{ "mcpServers": { "uxlint": { "command": "npx", "args": ["-y", "@uxlint-net/uxlint", "mcp"] } } }uxlint is also in the MCP Registry as
io.github.uxlint-net/uxlint, for clients that browse it. Already have the CLI? uxlint mcp install
registers it directly, no npx wrapper.
There is no token to set up first: ask your agent to audit something while signed out and it hands you
a sign-in link that mints and saves the token for you (UXLINT_API_KEY is for CI, which has no
browser).
Five tools: audit_url (full audit, graded verdict + action plan), verify_fix (recheck one rule
on one page after an edit), get_shot (fetch a finding's annotated screenshot),
ux_guidance (best-practice guidance to read before building UI), and lint_feedback — opt-in
and off by default (§ Privacy) — one tool for three kinds of signal: whether a finding was useful,
a lint uxlint is missing, or a component library it didn't recognise. The agent audits, reads the
fixes, edits, and re-audits until green.
Verification and design memory
verify_fix returns passed, failed, not_evaluated or inconclusive. Zero findings alone
never means a fix passed. Passing verification currently covers page-title-missing,
html-lang-missing and horizontal-overflow, with explicit evidence for the requested route and
both viewports. Other checks can report failures but need a full audit and evidence review;
unknown rules, skipped checks and old servers cannot pass. A cleared check never submits an
automatic acceptance vote.
Keep approved project decisions in uxlint.design.json beside uxlint.toml. ux_guidance reads
it afresh each time, including in a new agent session. Start with a draft:
{"version":1,"revision":1,"status":"draft","site":"example.test",
"tokens":{"accent":"var(--color-brand)"},
"components":{"primary_action":"Reuse PrimaryButton"},
"pages":{"/":"Explain the product and offer a clear starting action"},
"journeys":["Start the main task from the homepage"],
"references":["/styleguide"],"exceptions":[]}Set site to the project's configured site. Review the decisions with the owner before setting
status to approved and committing the file. Increment revision for subsequent approved
changes. The tool never approves or writes the contract; drafts do not become guidance. References
are not automatically fetched, exceptions do not suppress lints, and this initial local memory
does not yet enforce tokens or compare screenshots. Invalid contracts produce a visible warning.
Keep the file below 32 KiB and do not put credentials or private customer data in it.
Privacy & trust
This CLI runs on your machine and drives a real browser against real pages, so it's fair to ask exactly what it captures and where it goes. What we can tell you, because it's what the code in this repo actually does:
The collector is baked in and readable. It's compiled into this binary (
include_str!ofassets/collector.js), souxlint --versionpins the exact capture code and the server can't inject anything at run time. Everything it captures is page geometry, visible text, computed styles, and screenshots. For an embedded<iframe>it records the src's host only — never the full embed URL, which can carry session ids and tokens in its query string. It never reads your source code or your filesystem beyonduxlint.toml. It does read a little project provenance and send it with the report: your current git commit sha and branch name (git rev-parse), the machine's hostname, and, in GitHub Actions, the repo/PR/commit link. SetUXLINT_RUNNERto override the hostname.Secret & PII redaction is best-effort, not a guarantee. Before anything is uploaded, the collector masks text that looks like a token, API key, password, or email address in captured page text, and redacts the same patterns from console logs and native dialog messages. All channels share one pattern list (
assets/redact.js), so they can't drift. Screenshots get an extra pass right before capture: every form field value is masked (passwords blanked, other inputs replaced with dots) and pattern-matched secrets in on-page text are scrubbed, so typed data and displayed keys don't land in the image. That pass reaches into shadow DOM (including closed roots, via anattachShadowinterceptor) and same-origin iframes, and covers a cross-origin iframe with an opaque box since its pixels can't be redacted. But redaction is pattern-based, and a screenshot is still pixels: arbitrary displayed content that no pattern catches (a customer name on the page, order data), split-up values, and anything drawn into images or<canvas>can still slip through. Credentials you pass with--header/--storage/--login-*drive your browser only and are never sent to uxlint's server.Because a report captures page HTML, text, and screenshots, it is impossible to fully guard against sensitive content leaking into it. Use TEST accounts, not real or production ones. For local development the risk is low, as long as the data is only local development data. When you audit an authenticated site that holds real secrets or personal data, review what gets sent before you send it: use
--dry-runto write the exact payload (page text, provenance, and screenshots) to a local folder and inspect it without uploading. Redaction reduces accidental exposure; it is not a security boundary, and you remain responsible for what you point uxlint at.Navigational text is scrubbed for secrets only, on purpose. Control labels, menu and
<select>options, and workspace/org switcher names run through the same secret patterns, but they are not redacted for names or other arbitrary content. The reason is the goal walk: an audit drives the page with an LLM that reads exactly this text to find the right control, operate it, and match its choice back to the DOM. Masking it would defeat the walk, because the judge could no longer tell two options apart or click the one it picked. So the labels an audit needs to navigate stay readable, and a real name that rides along in one of them is covered by the test-accounts rule above rather than by redaction. This is a deliberate trade: keeping the goal walk working is worth more than blanking text the test-accounts rule already protects.No telemetry. This binary makes outbound calls to exactly the hosts you tell it to: the uxlint API server (
--server/UXLINT_SERVER, or the default hosted origin), the site you ask it to audit, and, only if you explicitly opt in, anonymous rule-feedback signals. There is no separate analytics/crash-reporting/phone-home destination baked in anywhere.Feedback is opt-in, off by default.
uxlint initasks once; it only ever writesfeedback = truetouxlint.tomlif you say yes, and you can flip it back at any time.The audit browser uses an ephemeral profile. Each audit launches Chrome with a fresh, throwaway user-data directory, so no cookies, history, or extensions from your everyday browsing are ever loaded into the audited session, and nothing persists after the process exits.
Your login stays local.
uxlint auth loginstores a token at~/.config/uxlint/credentials, chmod'd0600. It's never logged, never printed (except the one deliberate case:uxlint signupprints a freshly minted key so you can export it), and never bundled into a report.
This isn't a substitute for reading the source. It's short, and that's rather the point of publishing it. If you find something that doesn't match this description, please open an issue.
What this CLI is not
It's deliberately dumb: navigate, run the baked-in collector, upload the snapshot, print the
report. The rules, thresholds, and judge model are not in this repo and never will be. They're
the actual product, and they live server-side only. A build of this CLI is useless without a
uxlint server to talk to (the hosted one at https://uxlint.net by default, or your own).
License
Apache License 2.0 (see LICENSE). Read it, audit it, fork it, build it from source, ship it
inside your own tooling — no conditions beyond the usual attribution and patent terms.
This used to be the Business Source License, which converted to Apache-2.0 on a Change Date in 2030; we've simply arrived early. The restriction it carried — no competing hosted "audit my site" service built on this code — was protecting the wrong thing: what's valuable is the rules, the calibrated thresholds and the judge, and those are server-side and not in this repo. What IS here is a client that needs a uxlint server to be worth anything, and a client is exactly the piece that should be frictionless to install, read and vendor.
Releases up to and including v0.1.30 were published under BUSL-1.1; v0.1.31 onward are Apache-2.0.
Available Tools
5 toolsaudit_urlA
Audit a website's UX/design: contrast, tap targets, type scale, colour discipline, copy clarity, scan patterns. Each finding returns its RULE name (pass it to verify_fix), a SOURCE file:line hint (for local audits, grepped from the project you're in), the SELECTOR, the concrete FIX, and — for copy issues — the exact text EDIT (replace X with Y).
WORKFLOW: (1) Before you change anything, call ux_guidance for the area(s) the findings touch (forms, lists, layout, copy, …) so you fix toward the idiomatic, DRY pattern — not a one-off patch. If the result names a STYLEGUIDE, open it first and build to the components/tokens it shows. (2) Open the source line and apply the SMALLEST fix that reuses the project's existing components/tokens and voice (don't add a new one-off to silence the finding) without regressing the quality floor — responsive, visible keyboard focus, reduced motion, no new layout shift — then verify_fix. (3) Iterate until green. If a lint_feedback tool is in your tool list, also send a verdict for each finding you act on — it's how rules get kept, tuned or retired. It is absent unless the project set feedback = true (via uxlint init), so don't go looking for it: this result tells you when it's there.
SAFETY: interaction probes navigate, read, and click candidate menu/disclosure/dialog controls. Discovery skips recognised action words — delete, remove, accept, leave, revoke, pay, publish, add, create, save — using the full label. Labels cannot guarantee a click has no side effects; use an environment you control with disposable data. the write probes (which click Add/Create, and Delete through its confirm dialog) need the CLI's own --allow-mutation flag, which is not reachable from here. Declared tests are the exception and the only one: if the project's uxlint.toml declares tests that sign in as a persona, running them will SUBMIT forms and may DELETE items — that's what a test does, and it exercises create/delete flows on your own app. Point it only at an app you own / a throwaway env, never a site you don't control.
SETUP: in a project with no uxlint.toml, this returns the exact config to write first (org/site/base/routes) — write that file, check it in, then call again. Without it a local target can't be audited at all and a public one files its report under a site nobody chose.
AUTH: for a logged-in site, DON'T pass secrets here — credentials come from the project's uxlint.toml [personas] (the local client replays them; nothing touches this tool call or the transcript). If the audit hits a login wall, this tool returns the exact setup instructions.
| Name | Required | Description | Default |
|---|---|---|---|
| base | No | Base URL to audit — an ORIGIN like http://localhost:5173, NOT a path (a path gets appended to every route and mis-crawls). Optional: omit to use the `base` in the project's uxlint.toml. | |
| crawl | No | Max routes to discover and audit from the seeds (default 12). Set 0 to audit only the given routes. | |
| judge | No | Run the AI copy/design judge (prose quality, test-run navigation). ON by default; set false for a fast, deterministic-only pass while iterating. | |
| tests | No | Run the site's declared tests (whole-site reachability). ON by default; auto-scoped to crawling audits. Set false to skip for speed. Tests are a paid-plan feature — on a free plan, tests declared but not run print a one-line skip warning instead. | |
| detail | No | `full` for every finding's fix, best practice, rect and screenshot URL in the structured result. Default is compact: every finding, with each rule's fix said once — the full form can run past a client's output limit on a big site. | |
| routes | No | Comma-separated routes (default /) | |
| states | No | Drive hover/focus/keyboard interaction states — catches dead hover styles, hover-only content unreachable by touch/keyboard, illogical focus order, keyboard traps, form-validation gaps. ON by default; set false to skip it (faster) on large public crawls. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden — and it delivers: SAFETY discloses that probes navigate/read/click controls, skips destructive labels, requires --allow-mutation for write probes, and that declared tests will SUBMIT/DELETE data. SETUP and AUTH additionally disclose what happens with missing config (returns setup instructions) and how credentials are handled (via uxlint.toml [personas], nothing touches the transcript). This is exceptionally transparent for an unannotated tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but well structured with bold section headers (WORKFLOW, SAFETY, SETUP, AUTH) and a front-loaded opening that states purpose and result shape. Some redundancy remains — the disposable-environment warning repeats in SAFETY and the final sentence — but every section earns its place given the zero annotations and complex safety profile.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The combination of seven schema-covered parameters, no annotations, and no output schema would typically leave gaps, but the description covers the result format per finding, the required pre/post steps (ux_guidance, verify_fix, lint_feedback), setup behavior, login-wall behavior, and auth handling. An agent given this text has everything needed to invoke audit_url correctly and interpret its findings.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already fully documents all seven parameters (base, crawl, judge, tests, detail, routes, states), including types, defaults, and edge cases like 'base must be an ORIGIN, not a path'. The description adds contextual workflow around the parameters (e.g., base in setup config) but no new parameter-semantic meaning, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Audit) and resource (website's UX/design) with explicit dimensions (contrast, tap targets, type scale, colour discipline, copy clarity, scan patterns). The opening sentence also describes the result shape (RULE, SOURCE, SELECTOR, FIX, EDIT), separating it from siblings like get_shot and get_report, which handle visuals and report display rather than auditing.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The WORKFLOW section explicitly tells the agent to call ux_guidance before making changes and verify_fix after each fix, and names the exact iteration loop. It also instructs to send a verdict to lint_feedback when present, and to write the config file if none exists. It does not define explicit exclusion conditions for get_shot or get_report, but the sequencing of audit → guidance → verify is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_reportA
Read an EXISTING report's findings — one the user started from the dashboard, a run whose audit_url call you lost, or one that TIMED OUT (it keeps whatever it found before the cap, and says so). Pass the report's URL as the user sees it (…/r/) or its id. Returns the same thing audit_url does: the grade, what moved since the last run, and every finding with its rule, location, source hint, fix and screenshot_url — so you can act on it and confirm each fix with verify_fix. Reports are private; this reads them with your uxlint login.
| Name | Required | Description | Default |
|---|---|---|---|
| detail | No | `full` for every finding's fix, best practice, rect and screenshot URL in the structured result; compact by default (see audit_url). | |
| report | Yes | The report to read: its URL as the dashboard shows it (`https://uxlint.net/sites/8/r/abc123`), a `/r/…` path, or the bare report id. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description carries the full burden, and it delivers: it labels the operation as a read, discloses that timed-out reports preserve partial findings and say so, and notes reports are private and read with the user's uxlint login. It also commits to a stable output shape by enumerating the returned fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core purpose, and each sentence adds a distinct fact: use cases, input formats, return payload, and privacy/auth. It is longer than minimal but dense and without filler, though the parenthetical examples could be slightly tightened.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates by enumerating the returned grade, deltas, and each finding's fields, and by explaining timeout behavior and auth requirements. It does not cover error cases or exact formatting, but the schema handles parameter formatting, making this complete enough for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already documents both parameters with 100% coverage, so the baseline is 3. The description restates the report parameter's accepted URL/path/id forms but adds no new semantic detail beyond the schema; detail's full-vs-compact behavior is delegated to audit_url and already covered in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb-resource pair ('Read an EXISTING report's findings') and immediately distinguishes the tool from siblings by mentioning audit_url and verify_fix. It makes the scope explicit: existing reports, including timed-out ones, not new audits.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It clearly identifies when to use get_report: reports started in the dashboard, lost audit_url calls, or timed-out runs. It does not explicitly say 'use audit_url for new audits', but 'EXISTING' and the audit_url reference make the boundary inferable, giving clear context without a formal when-not clause.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_shotA
View a report's annotated screenshot — the flagged element boxed on its page. Reports are PRIVATE, so a finding's screenshot_url can't be fetched with a plain GET; this tool fetches it with your uxlint login. Pass the finding's screenshot_url (from audit_url / verify_fix). Returns the image inline (if your client renders MCP images) and always writes it to a local file whose path you can open/Read.
| Name | Required | Description | Default |
|---|---|---|---|
| screenshot_url | Yes | The `screenshot_url` from an audit_url / verify_fix finding — the annotated shot with the flagged element boxed. A full URL or a `/r/…` path on your uxlint server. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full burden. It discloses that reports are PRIVATE, reads requires the user's uxlint login, returns image inline (if client supports MCP images), and always writes to a local file. This adds significant behavioral context beyond what an annotation might provide, such as side effects (writing a file) and authentication requirements. The only minor gap is not detailing the exact file path or cleanup behavior, but the description is quite transparent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise (about 3 sentences) and front-loads the core action. Every sentence provides essential information: purpose, why it's needed, what to pass, and what happens. No fluff or redundancy. The structure is logical: what, why, how, outcome.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given that there is only one parameter, no output schema, and no annotations, the description is complete. It covers the tool's purpose, usage, parameter source, return behavior (inline and local file), and the limitation about private reports. This is sufficient for an agent to select and correctly invoke the tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and it already explains the screenshot_url parameter clearly. The description adds contextual meaning by tying the parameter to the finding's screenshot_url and specifying the source (audit_url/verify_fix). It also clarifies that the URL can be a full URL or a /r/… path. This adds value beyond the schema, so a slightly above baseline score is warranted.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: to view a report's annotated screenshot, with the flagged element boxed. It also distinguishes it from siblings by explaining why a plain GET won't work and that it requires the finding's screenshot_url. The verb 'View' and specific resource 'report's annotated screenshot' are precise.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly explains when to use this tool (to fetch a screenshot_url from audit_url/verify_fix findings) and why it's necessary (reports are private, plain GET won't work). It also provides context that the screenshot URL comes from specific sources, serving as an alternative to direct fetching. This is exactly the kind of usage guidance expected.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ux_guidanceA
Project design memory and best-practice UI guidance to read BEFORE building or changing UI — usability, consistency, and performance patterns distilled from uxlint's audit corpus, so you build idiomatic, DRY, testable components the first time instead of getting audited after. Reads the nearest project’s uxlint.design.json on each call; only explicitly approved versioned decisions guide edits. Never auto-approve or rewrite that contract to silence a lint. Covers whole-row click targets, single-column labelled forms, tabs/radiogroup vs plain buttons, one shared width scale + aligned panels, pagination by scroll length, CLS-safe layout, and copy that reads as UI (active voice, honest labels, useful empty/error states). Each item names the uxlint rule that catches a miss, so the loop is: read the topic, build to it, then audit_url to confirm.
| Name | Required | Description | Default |
|---|---|---|---|
| topic | No | Which area to get guidance for: layout, forms, lists, navigation, components, performance, accessibility, content. Omit for the index of topics; "all" for everything. Accepts aliases (copy, nav, a11y, perf, dry, …) and falls back to the index for anything unrecognized. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the transparency burden and does well: it discloses that each call reads the nearest project's uxlint.design.json, only explicitly approved decisions guide edits, and it warns against auto-approving or rewriting the contract. This gives an agent realistic expectations about read-only, project-scoped behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense and front-loaded with purpose and timing, then packs useful specifics about covered topics and the lint-rule loop. It is somewhat long and runs several ideas into one block, but every section contributes actionable guidance.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description is complete enough for an agent to call the tool and act on the result: it explains what the tool reads, what areas it covers, how it relates to lint rules, and how it fits with audit_url. It does not describe the exact return format, but that is a minor gap given the tool's guidance role.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already documents the single topic parameter at 100% coverage, including defaults, examples, aliases, and fallback behavior. The description adds no further parameter-level detail, so the baseline score of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action (read guidance before building/changing UI) and a resource (project design memory / uxlint.design.json). It clearly distinguishes its role from siblings by framing it as the pre-build step in the loop that ends with audit_url.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly says when to use the tool ('read BEFORE building or changing UI') and gives a workflow: read the topic, build to it, then confirm with audit_url. It does not enumerate when to prefer siblings like get_shot, but the sequencing and the warning about not rewriting the contract provide strong usage context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
verify_fixA
After editing to fix a finding, re-check ONE rule on ONE page — the 'did my fix land?' loop, far quicker than a full re-audit (one route, no crawl, no judge). Returns whether the rule still fires, AND names any OTHER deterministic findings now on that page (the regression guard — so a fix that clears your rule but breaks something else here doesn't read as all-clear). Returns status passed, failed, not_evaluated or inconclusive. A pass requires explicit server evidence for the requested route and both viewports. Currently supported passing checks: page-title-missing, html-lang-missing, horizontal-overflow. Other rules can report observed failures but cannot pass without execution evidence; re-run audit_url for judge, interaction and site checks. Unknown rules and missing evidence never clear. A cleared finding is not a user endorsement of the fix.
| Name | Required | Description | Default |
|---|---|---|---|
| base | No | Base URL — an ORIGIN like http://localhost:5173, NOT a path. Optional: omit to use the `base` in the project's uxlint.toml. | |
| rule | Yes | The rule to verify is gone, e.g. contrast, tap-target, unlabelled-field | |
| route | No | The route to check, e.g. /pricing (default /) | |
| states | No | Drive interaction states (needed for state/form/interaction rules) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure. It does a good job: discloses that the tool only reports observed failures for rules not in the supported passing list, that unknown rules and missing evidence never clear, and that a cleared finding is not a user endorsement of the fix. It also explains the regression guard behavior. It does not explicitly state whether the operation is read-only or has side effects, but given the described behavior (a check), this is implicit. One might argue for a 5, but the lack of explicit mention of side-effect-freeness or any destructive potential is a tiny gap; still, it's quite thorough.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a solid paragraph, slightly long but information-dense. It front-loads the purpose, then adds critical caveats. It could be split into bullet points for readability, but every sentence earns its place — no filler. The length is justified given the complexity (supported rules, evidential requirements, regression guard, exclusions).
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with no output schema and no annotations, the description does an excellent job of covering everything an agent needs: what it does, when to use it, what the return statuses mean, what constitutes a pass (explicit server evidence for the requested route and both viewports), which rules are supported for passing, what happens for other rules, and how to handle judge/interaction/site checks. It also mentions the regression guard, covering the risk of a fix breaking something else. Very complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all four parameters. The description adds context about the rule parameter (which rules are supported for passing) and hints at the interaction states for state/form/interaction rules, but does not add substantial new semantics beyond what's in the schema. The description does not mention default values or relationships that are not already present in the schema. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states the specific verb ('re-check'), resource ('ONE rule on ONE page'), and purpose ('did my fix land?'). It clearly distinguishes itself from a full re-audit by naming the alternative (audit_url) and explaining the difference (one route, no crawl, no judge). The description is not a tautology; it explains the tool's role in the fix-verify workflow.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states when to use this tool (after editing to fix a finding, to verify a specific fix) and when not to use it (for judge, interaction and site checks — says to re-run audit_url for those). It also names the sibling tool audit_url as the alternative. It provides clear conditions: a pass requires explicit server evidence for the requested route and both viewports, and unsupported rules cannot pass. This is explicit and actionable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
2 tool updates
v0.1.41- Changed
audit_url1 field changed- added
Input schema / properties / detailAdded value: +{ + "default": null, + "description": "`full` for every finding's fix, best practice, rect and screenshot URL in the structured\nresult. Default is compact: every finding, with each rule's fix said once — the full form can\nrun past a client's output limit on a big site.", + "type": [ + "string", + "null" + ] +}
- Added
get_report
4 tool updates
- First observed
audit_url - First observed
get_shot - First observed
ux_guidance - First observed
verify_fix
TDQS
Scored across 5 tools
Each tool targets a distinct phase of the UX lint workflow: guidance, audit creation, report retrieval, screenshot viewing, and fix verification. Even though audit_url and get_report both return findings, one kicks off a new audit while the other reads an existing report, so there is no realistic confusion.
Audit_url, get_shot, get_report, and verify_fix all follow a clear verb_noun pattern. ux_guidance breaks that pattern as a noun_noun name, but it is still readable and does not undermine the overall consistency of the set.
Five tools is a well-scoped size for a UX auditing tool: guidance, audit, report, screenshot, and verify each earn their place. There is no redundancy or bloat.
The tool surface covers the full loop: read guidance, audit a page, retrieve an existing report, view visual evidence, and verify fixes. The optional lint_feedback tool is explicitly conditional and therefore not a real gap.
Maintenance
Related MCP Connectors
Score any URL against a real design contract — 42 checks, A-F grade, token + motion validation.
Scan a web page for accessibility, security, privacy, quality and SEO issues, with fixes.
AI website audit: security, SEO, performance, UX and accessibility checks with actionable fixes.
Audit public webpages and supplied markup for HTML, CSS, SEO, JSON-LD, and link issues.
Related MCP Servers
- AlicenseAqualityDmaintenanceAudit any website for privacy, security, accessibility, and performance issues — with scores, grades, and actionable fix instructions. No account required.34 npmMIT
- FlicenseNot gradedqualityDmaintenanceEnables automated WCAG 2.2 AA accessibility audits of Figma designs and webpages. Generates detailed markdown reports with severity-grouped violations, specific criterion references, and concrete fix recommendations.-
- AlicenseAqualityCmaintenancePoint your coding agent at a URL and get a real-browser QA audit: broken signup/login/checkout flows, JS console errors, missing analytics, consent + security headers, mobile tap targets, and accessibility — returned as machine-verified findings graded A-F.442Apache 2.0
- AlicenseNot gradedqualityCmaintenanceDesign review for UI code, inside your coding agent. Reviews React, Vue, Svelte, CSS and SwiftUI against 313 rules and returns scored findings with file:line fixes your agent can apply and verify.MIT