protogrid

Search / io.github.igrlk/uiverify

UI Verify

R2· OAuth, once

MCP server for visual regression testing: triage a PR's UI diffs from your coding agent.

v1.1.0 · active · repository · website · descriptor JSON · versions

An agent can connect after a one-time OAuth consent by a human.Remote endpoint behind OAuth 2. Tokens stay with the agent; the registry only exposes the authorization metadata.
Quality87good
Trust93of 100
Uptime, 30 days100%
Latency p50471 ms

Connect

8 clients · secrets stay placeholders
{
  "mcpServers": {
    "uiverify": {
      "type": "http",
      "url": "https://uiverify.ai/mcp"
    }
  }
}
claude mcp add --transport http uiverify https://uiverify.ai/mcp
[mcp_servers.uiverify]
url = "https://uiverify.ai/mcp"
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "uiverify": {
      "type": "remote",
      "url": "https://uiverify.ai/mcp",
      "enabled": true
    }
  }
}
{
  "mcpServers": {
    "uiverify": {
      "type": "http",
      "url": "https://uiverify.ai/mcp"
    }
  },
  "deeplink": "cursor://anysphere.cursor-deeplink/mcp/install?name=uiverify&config=eyJ0eXBlIjoiaHR0cCIsInVybCI6Imh0dHBzOi8vdWl2ZXJpZnkuYWkvbWNwIn0%3D"
}
{
  "servers": {
    "uiverify": {
      "type": "http",
      "url": "https://uiverify.ai/mcp"
    }
  }
}
{
  "mcpServers": {
    "uiverify": {
      "httpUrl": "https://uiverify.ai/mcp"
    }
  }
}
extensions:
  "uiverify":
    enabled: true
    name: "uiverify"
    type: streamable_http
    uri: "https://uiverify.ai/mcp"
    timeout: 300

Quality 87 / 100good

protocoln/a · weight 25
  • n/a
    protocol.modern, protocol.stateless, protocol.transport, protocol.list_ttlno remote answered a protocol handshake (not probed yet, unreachable, or local-only)
authorization100 · weight 15
  • pass
    auth.prmProtected Resource Metadata (RFC 9728) published
  • pass
    auth.as_metadataauthorization server metadata reachable
  • pass
    auth.cimdClient ID Metadata Documents supported
  • n/a
    auth.secret_in_urlno templated URL
tool hygiene86 · weight 30
  • pass
    tools.descriptionsevery tool has a description
  • warn
    tools.description_length3 tools have descriptions over 1,024 characters, which crowds the context
  • pass
    tools.schemasevery tool has an object input schema
  • pass
    tools.annotations15 of 15 tools declare readOnlyHint or destructiveHint
  • warn
    tools.directory_hints6 of 15 tools declare all four hints; missing: render_diff_image (destructiveHint, idempotentHint); list_comments (destructiveHint, idempotentHint); get_build (destructiveHint, idempotentHint); …
  • pass
    tools.token_costabout 5,910 tokens to load every tool
  • pass
    tools.api_dumptools are not a one-to-one API dump
stability75 · weight 15
  • warn
    stability.changes24 tool changes in 30 days
  • pass
    stability.rug_pullno tool changed its meaning under the same name
dependenciesn/a · weight 15
  • n/a
    deps.known_vulns, deps.mcp_sdk_version, deps.resolvableno npm or PyPI package

15 tools, about 5,910 tokens to load them all · tool set 33cf2d87b865 · tools last changed 2026-10-18 · checked 2026-10-20 10:35 UTC

Tool changes

  • delete_commentchangeddescription
    before

    Soft-delete a comment (get its id from list_comments). An agent can delete only agent-authored comments, never a human's. Deleting a thread root removes its replies too. Requires the image comments feature.

    after · 86% of words in common

    Soft-delete a comment (get its id from list_comments). An agent can delete only agent-authored comments, never a human's. Deleting a thread root removes its replies too.

  • resolve_commentchangeddescription
    before

    Mark a comment thread resolved or reopen it (get the id from list_comments). Resolving stamps the thread ROOT, so pass a root comment's id - a reply id is a no-op. Any team writer may toggle this. Requires the image comments feature.

    after · 91% of words in common

    Mark a comment thread resolved or reopen it (get the id from list_comments). Resolving stamps the thread ROOT, so pass a root comment's id - a reply id is a no-op. Any team writer may toggle this.

  • update_commentchangeddescription
    before

    Replace the body of a comment (get its id from list_comments). An agent can edit only agent-authored comments, never a human's. Requires the image comments feature.

    after · 88% of words in common

    Replace the body of a comment (get its id from list_comments). An agent can edit only agent-authored comments, never a human's.

  • post_commentchangeddescription
    before

    Leave a review comment on one of a build's changed-story diffs (resolve the build by commitSha/prNumber/buildId, target the diff by diffResultId from get_build/get_diff). The comment is authored as the agent. Optionally anchor it to a spot on the candidate image with `anchor`: omit or null for a whole-diff comment, {type:'point',x,y} to pin a point, {type:'rect',x,y,w,h} for a box, or {type:'path',points:[{x,y},...],closed} for a shape - all coordinates 0..1 normalized to the candidate image. `side` picks the pane ('after' the candidate, default; 'before' the baseline). Pass `parentId` (a root comment id from list_comments) to REPLY in that thread instead - a reply inherits the root's side and carries no anchor, so `anchor`/`side` are ignored. A new root comment is refused when a newer build exists on the branch (comment on the latest build); replies stay allowed. Requires the image comments feature.

    after · 98% of words in common

    Leave a review comment on one of a build's changed-story diffs (resolve the build by commitSha/prNumber/buildId, target the diff by diffResultId from get_build/get_diff). The comment is authored as the agent. Optionally anchor it to a spot on the candidate image with `anchor`: omit or null for a whole-diff comment, {type:'point',x,y} to pin a point, {type:'rect',x,y,w,h} for a box, or {type:'path',points:[{x,y},...],closed} for a shape - all coordinates 0..1 normalized to the candidate image. `side` picks the pane ('after' the candidate, default; 'before' the baseline). Pass `parentId` (a root comment id from list_comments) to REPLY in that thread instead - a reply inherits the root's side and carries no anchor, so `anchor`/`side` are ignored. A new root comment is refused when a newer build exists on the branch (comment on the latest build); replies stay allowed.

  • list_commentschangeddescription
    before

    Every review comment on a build's changed stories (resolved by commitSha/prNumber/buildId), each carrying its diffResultId, author (human name or 'agent'), body, createdAt, and anchor - where on the candidate image it points: null (whole diff), {type:'point',x,y}, {type:'rect',x,y,w,h}, or {type:'path',points,closed}, all normalized 0..1 to the candidate image. Use it to read what a designer/QA (or another agent) flagged on a screenshot before acting. Requires the image comments feature.

    after · 95% of words in common

    Every review comment on a build's changed stories (resolved by commitSha/prNumber/buildId), each carrying its diffResultId, author (human name or 'agent'), body, createdAt, and anchor - where on the candidate image it points: null (whole diff), {type:'point',x,y}, {type:'rect',x,y,w,h}, or {type:'path',points,closed}, all normalized 0..1 to the candidate image. Use it to read what a designer/QA (or another agent) flagged on a screenshot before acting.

  • delete_commentchangeddescription
    before

    Soft-delete a comment (get its id from list_comments). An agent key can delete only agent-authored comments, never a human's. Deleting a thread root removes its replies too. Requires the image comments feature.

    after · 97% of words in common

    Soft-delete a comment (get its id from list_comments). An agent can delete only agent-authored comments, never a human's. Deleting a thread root removes its replies too. Requires the image comments feature.

  • update_commentchangeddescription
    before

    Replace the body of a comment (get its id from list_comments). An agent key can edit only agent-authored comments, never a human's. Requires the image comments feature.

    after · 96% of words in common

    Replace the body of a comment (get its id from list_comments). An agent can edit only agent-authored comments, never a human's. Requires the image comments feature.

  • post_commentchangedinput schema
  • accept_buildchangedinput schema
  • review_diffchangeddescription
    before

    Record a review on a single diff result (get diffResultId from get_build/get_diff). 'accept' makes the candidate the new baseline for that story on its branch, so the next build is clean; 'deny' records the rejection without changing the baseline; 'ignore' excludes the story from the gate persistently (the snapshot keeps differing on future builds but no longer flags the check) — use it for an intentional, ongoing diff like an animation or a live timestamp. This is the same accept/deny/ignore as the dashboard, attributed to your project key. Use after you've inspected the diff (e.g. with render_diff_image) and decided intended vs. regression. accept and ignore are refused while the story has an unresolved review comment (read it with list_comments, address it, resolve_comment the thread, then retry); deny is always allowed.

    after · 93% of words in common

    Record a review on a single diff result (get diffResultId from get_build/get_diff). 'accept' makes the candidate the new baseline for that story on its branch, so the next build is clean; 'deny' records the rejection without changing the baseline; 'ignore' excludes the story from the gate persistently (the snapshot keeps differing on future builds but no longer flags the check) — use it for an intentional, ongoing diff like an animation or a live timestamp. This is the same accept/deny/ignore as the dashboard, attributed to the agent (and to you, when you logged in). Use after you've inspected the diff (e.g. with render_diff_image) and decided intended vs. regression. accept and ignore are refused while the story has an unresolved review comment (read it with list_comments, address it, resolve_comment the thread, then retry); deny is always allowed.

Showing the latest 10. Full history: list_changes · trend: quality JSON.

Checks run on what our credential-free, read-only probes observe; tools are never called and no code audit is performed. How it is computed.

Trust 93 / 100

provenance75
liveness100
freshness100
hygiene100

+repository +website +reachable +uptime-100% +updated-0d-ago

Derived from observable signals (official registry feed and our own credential-free probes); no code audit performed. How it is computed.

Endpoints

remoteauthreachableuptime 30dp50protocollast ok
https://uiverify.ai/mcp streamable-httpoauth2 AS: https://wise-celebration-01.authkit.appyes100%471 ms–2026-10-20

Tools (15)

accept_buildAccept ALL changed stories in one build at once (resolved by commitSha/prNumber/buildId), advancing each story's per-branch baseline so the next build is clean. This is the bulk form of review_diff='accept' — use it when you've decided the whole build's changes are intended. It accepts every changed story, including stories that already have a prior denied review; failed stories are unaffected. Returns the build triage after accepting (first page of changed stories, each now showing decision='accepted'; page the rest with list_build_stories if changedNextCursor is set). Refused, with nothing accepted, while any changed story has an unresolved review comment: the error names those stories; read them with list_comments, address each note, resolve_comment its thread, then accept again.
delete_commentdestructiveSoft-delete a comment (get its id from list_comments). An agent can delete only agent-authored comments, never a human's. Deleting a thread root removes its replies too.
get_buildread-onlyTriage one build, resolved by commitSha, prNumber, or buildId (exactly one). Returns the gate verdict and counts (total/changed/failed/unchanged), then the FIRST page (25) of the changed stories (story id, viewport, % pixels changed, review decision, the AI verdict aiVerdict=intended|regression + aiConfidence, and for a regression the judge's one-line aiFlagReason=what-looks-unintended, when AI review is on, and the story's own review-comment tally comments {total, unresolved}) and the first page of failed stories (failedStories[].kind is `render` when the story produced no frame, or `interaction` when it rendered and its play() assertion threw; failedStories[].error is the message's first line, errorTruncated marks the ones that carried more). When AI review ran, aiReview tallies how many changes look like regressions vs intended, and the changed list is ordered likely-regressions-first. changedNextCursor / failedNextCursor are non-null when there are more than 25: page the rest with list_build_stories. counts.unchanged is how many stories did NOT change and have a baseline - this triage call does NOT list them (keeps the response lean); call list_build_stories status=unchanged to browse them (e.g. to confirm a passed build's stories are 'identical to baseline'). comments is the build-wide review-comment tally {total, unresolved}: unresolved>0 means a designer/QA (or another agent) left an open note on a story - read it with list_comments BEFORE you accept. No image URLs here - call get_diff or render_diff_image for pixels.
get_diffread-onlyPer-story diff detail for a build (resolved by commitSha/prNumber/buildId). Returns diff metrics and presigned, time-limited URLs (download them to a file, or link them in a PR comment) for the baseline, candidate, and diff PNGs. Defaults to the changed stories; pass storyId for one specific story. When that storyId is an UNCHANGED story it returns its baseline (diffResultId null, changed false, the baseline URL as both baselineUrl and candidateUrl) - the story rendered identical to baseline. Use render_diff_image instead when you want the actual pixels inline for a vision model, not a URL. When AI review is on, each diff carries the judge's call: aiVerdict (intended|regression), aiConfidence, aiSummary (what changed), aiReasoning, and aiFlagReason; all null when AI review didn't run for it. Each diff also carries comments {total, unresolved} for THAT story - unresolved>0 means an open review note; read the thread with list_comments before accepting.
get_pr_changesetread-onlyThe cumulative 'this PR vs base' visual changeset (resolved by commitSha/prNumber/buildId) - what the whole PR does to the UI versus the branch it merges into, INDEPENDENT of what is left to review on the latest build. Unlike get_build (this commit vs the branch's own accepted baseline), this survives in-PR accepts: a story accepted mid-PR still shows under `changed` with status=accepted, so it answers 'what did this PR change' even after the gate reads clean. Returns base (the branch it merges into), counts {new,changed,removed,unchanged}, and the first page of `new` + `changed` + `removed` stories (storyId, title, name, kind, review status, aiVerdict). `removed` lists stories that HAD a baseline on the base branch but are gone from this PR's head (a deletion - otherwise invisible; each carries lastBuildId, the build that rendered its now-orphaned baseline). newNextCursor / changedNextCursor / removedNextCursor page the rest with list_pr_stories. No image URLs - fetch pixels by storyId with get_diff / render_diff_image. Requires the PR visual changeset feature.
list_buildsread-onlyRecent UI Verify builds for one project, newest first. Each row is a one-line verdict (gateStatus: passed | changed | failed) for a commit/PR — use it to find the build to inspect. No image URLs or per-story detail here: call get_build for the changed-story list, get_diff for images.
list_build_storiesread-onlyPage through one build's stories filtered by status (resolved by commitSha/prNumber/buildId). Use it to read past get_build's first page, or to browse the unchanged/passed stories get_build only counts. status='changed' returns changed stories (same shape + order as get_build, regression-first, each with its comments {total, unresolved}; unresolved>0 means an open review note - read it with list_comments first); status='failed' returns failed stories; status='unchanged' returns the stories that did NOT change this build but have a baseline on this branch (storyId, viewport, browser) - fetch any of their images by storyId with get_diff or render_diff_image to confirm 'identical to baseline'. Returns { stories, nextCursor }: pass nextCursor back as `cursor` for the next page; null means no more. limit defaults to 25 (max 100). Unchanged is only available once the build has settled (an in-progress build has rendered nothing, so it returns an empty page).
list_commentsread-onlyEvery review comment on a build's changed stories (resolved by commitSha/prNumber/buildId), each carrying its diffResultId, author (human name or 'agent'), body, createdAt, and anchor - where on the candidate image it points: null (whole diff), {type:'point',x,y}, {type:'rect',x,y,w,h}, or {type:'path',points,closed}, all normalized 0..1 to the candidate image. Use it to read what a designer/QA (or another agent) flagged on a screenshot before acting.
list_projectsread-onlyEvery UI Verify project you can access, across all the teams you are a member of, most recently built first. Each row carries the projectId to pass to list_builds, or to a commitSha/prNumber lookup, when you can access several projects, plus the team and project slugs, name, type (storybook | playwright | vitest | screenshot), repo, and lastBuildAt. Calls that take a buildId, diffResultId, or commentId never need a projectId.
list_pr_storiesread-onlyPage through the PR-vs-base changeset stories of one kind (resolved by commitSha/prNumber/buildId) - use it to read past get_pr_changeset's first page. kind='new' returns stories the PR adds that the base branch has no baseline for; kind='changed' returns stories whose image differs from the base branch's accepted image (even if accepted mid-PR, with status=accepted); kind='removed' returns stories that HAD a baseline on the base branch but are gone from head (a deletion; each carries lastBuildId, not a review status or verdict). Returns { stories, nextCursor }: pass nextCursor back as `cursor` for the next page; null means no more. limit defaults to 25 (max 100). Requires the PR visual changeset feature.
post_commentLeave a review comment on one of a build's changed-story diffs (resolve the build by commitSha/prNumber/buildId, target the diff by diffResultId from get_build/get_diff). The comment is authored as the agent. Optionally anchor it to a spot on the candidate image with `anchor`: omit or null for a whole-diff comment, {type:'point',x,y} to pin a point, {type:'rect',x,y,w,h} for a box, or {type:'path',points:[{x,y},...],closed} for a shape - all coordinates 0..1 normalized to the candidate image. `side` picks the pane ('after' the candidate, default; 'before' the baseline). Pass `parentId` (a root comment id from list_comments) to REPLY in that thread instead - a reply inherits the root's side and carries no anchor, so `anchor`/`side` are ignored. A new root comment is refused when a newer build exists on the branch (comment on the latest build); replies stay allowed.
render_diff_imageread-onlyFetch a story's image as an INLINE image (base64 pixels, not a URL) so a vision model can look at it directly. Needs a native MCP client that renders image content; piped through raw curl it is useless (use get_diff's URLs there instead). Two ways to address it: (1) diffResultId + which for a CHANGED story - which is baseline|candidate|diff (the triptych) or before_after, the baseline and candidate SIDE BY SIDE (before on the left, after on the right) cropped to the changed region - and when a story changed in SEVERAL far-apart places, one such crop PER region stacked top to bottom, so a header-plus-footer change is two tight crops, not a page-tall image. before_after is usually what you want for a code change - it zooms to what moved instead of a full page. Get diffResultId from get_build (changedStories[].diffResultId) or get_diff. (2) a build selector (commitSha|prNumber|buildId) + storyId for ANY story's current image - the candidate if it changed this build, else its baseline. This second form is the only way to see an UNCHANGED/passed story's pixels (list them via list_build_stories status=unchanged), so you can confirm 'identical to baseline'. Errors if the image doesn't exist (a genuinely new story has no baseline, so no before_after either). When the story has unresolved review comments, a text note saying so comes with the image: read them with list_comments before you accept.
resolve_commentMark a comment thread resolved or reopen it (get the id from list_comments). Resolving stamps the thread ROOT, so pass a root comment's id - a reply id is a no-op. Any team writer may toggle this.
review_diffRecord a review on a single diff result (get diffResultId from get_build/get_diff). 'accept' makes the candidate the new baseline for that story on its branch, so the next build is clean; 'deny' records the rejection without changing the baseline; 'ignore' excludes the story from the gate persistently (the snapshot keeps differing on future builds but no longer flags the check) — use it for an intentional, ongoing diff like an animation or a live timestamp. This is the same accept/deny/ignore as the dashboard, attributed to the agent (and to you, when you logged in). Use after you've inspected the diff (e.g. with render_diff_image) and decided intended vs. regression. accept and ignore are refused while the story has an unresolved review comment (read it with list_comments, address it, resolve_comment the thread, then retry); deny is always allowed.
update_commentReplace the body of a comment (get its id from list_comments). An agent can edit only agent-authored comments, never a human's.

Schemas: list_tools.

Similar MCP servers

Official server.json
{
  "name": "io.github.igrlk/uiverify",
  "title": "UI Verify",
  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
  "remotes": [
    {
      "url": "https://uiverify.ai/mcp",
      "type": "streamable-http"
    }
  ],
  "version": "1.1.0",
  "repository": {
    "url": "https://github.com/uiverify/uiverify",
    "source": "github"
  },
  "websiteUrl": "https://uiverify.ai",
  "description": "MCP server for visual regression testing: triage a PR's UI diffs from your coding agent."
}