{"name":"io.github.igrlk/uiverify","slug":"igrlk-uiverify","title":"UI Verify","description":"MCP server for visual regression testing: triage a PR's UI diffs from your coding agent.","url":"https://mcp.market/server/igrlk-uiverify","rating":null,"grade":"B","score":79,"certified":false,"status":"active","category":"ai","tags":["ai"],"presence":{"score":36,"stars":22,"forks":1,"downloads_week":null,"last_push_at":"2026-09-18T18:28:10.000Z","license":"MIT"},"uptime":{"percent":100,"checks":6,"ok":6,"last_checked_at":"2026-09-20T22:21:05.663Z","last_ok_at":"2026-09-20T22:21:05.663Z","latency_ms":628},"claimed":false,"transport":"remote","callable_via_gateway":true,"default_price_micros":0,"repository":"https://github.com/uiverify/uiverify","website":"https://uiverify.ai","version":"1.0.1","remotes":[{"type":"streamable-http","url":"https://uiverify.ai/api/mcp","headers":[{"description":"Bearer token: your UIVERIFY_API_KEY from your uiverify.ai project setup page.","isRequired":true,"isSecret":true,"name":"Authorization"}]}],"packages":[],"tools":[{"name":"accept_build","description":"Accept 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).","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"commitSha":{"type":"string","minLength":1,"description":"Resolve the build for this git commit SHA."},"prNumber":{"type":"integer","exclusiveMinimum":0,"description":"Resolve the latest build for this PR number."},"buildId":{"type":"string","format":"uuid","description":"Resolve this exact build id."}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"delete_comment","description":"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.","write_action":true,"price_micros":0,"input_schema":{"type":"object","properties":{"commentId":{"type":"string","description":"The comment id to delete (from list_comments)."}},"required":["commentId"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"get_build","description":"Triage 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 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.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"commitSha":{"type":"string","minLength":1,"description":"Resolve the build for this git commit SHA."},"prNumber":{"type":"integer","exclusiveMinimum":0,"description":"Resolve the latest build for this PR number."},"buildId":{"type":"string","format":"uuid","description":"Resolve this exact build id."}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"get_diff","description":"Per-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.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"commitSha":{"type":"string","minLength":1,"description":"Resolve the build for this git commit SHA."},"prNumber":{"type":"integer","exclusiveMinimum":0,"description":"Resolve the latest build for this PR number."},"buildId":{"type":"string","format":"uuid","description":"Resolve this exact build id."},"storyId":{"type":"string","description":"Limit to one story id."}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"get_pr_changeset","description":"The 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.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"commitSha":{"type":"string","minLength":1,"description":"Resolve the build for this git commit SHA."},"prNumber":{"type":"integer","exclusiveMinimum":0,"description":"Resolve the latest build for this PR number."},"buildId":{"type":"string","format":"uuid","description":"Resolve this exact build id."}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"list_build_stories","description":"Page 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); 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).","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"commitSha":{"type":"string","minLength":1,"description":"Resolve the build for this git commit SHA."},"prNumber":{"type":"integer","exclusiveMinimum":0,"description":"Resolve the latest build for this PR number."},"buildId":{"type":"string","format":"uuid","description":"Resolve this exact build id."},"status":{"type":"string","enum":["changed","unchanged","failed"],"description":"Which stories to page: changed, failed, or unchanged (baselined, didn't change this build)."},"cursor":{"type":"string","description":"The nextCursor from a prior page; omit for the first page."},"limit":{"type":"integer","minimum":1,"maximum":100,"description":"Page size (default 25, max 100)."}},"required":["status"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"list_builds","description":"Recent UI Verify builds for your 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.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"branch":{"type":"string","description":"Only builds on this git branch."},"status":{"type":"string","enum":["pending","preflight","running","passed","changed","failed","blocked"],"description":"Only builds with this raw status."},"limit":{"type":"integer","minimum":1,"maximum":100,"description":"Max builds to return (default 20)."}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"list_comments","description":"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.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"commitSha":{"type":"string","minLength":1,"description":"Resolve the build for this git commit SHA."},"prNumber":{"type":"integer","exclusiveMinimum":0,"description":"Resolve the latest build for this PR number."},"buildId":{"type":"string","format":"uuid","description":"Resolve this exact build id."}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"list_pr_stories","description":"Page 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.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"commitSha":{"type":"string","minLength":1,"description":"Resolve the build for this git commit SHA."},"prNumber":{"type":"integer","exclusiveMinimum":0,"description":"Resolve the latest build for this PR number."},"buildId":{"type":"string","format":"uuid","description":"Resolve this exact build id."},"kind":{"type":"string","enum":["new","changed","removed"],"description":"Which changeset stories to page: new (added), changed (vs base), or removed (deleted)."},"cursor":{"type":"string","description":"The nextCursor from a prior page; omit for the first page."},"limit":{"type":"integer","minimum":1,"maximum":100,"description":"Page size (default 25, max 100)."}},"required":["kind"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"post_comment","description":"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.","write_action":true,"price_micros":0,"input_schema":{"type":"object","properties":{"commitSha":{"type":"string","minLength":1,"description":"Resolve the build for this git commit SHA."},"prNumber":{"type":"integer","exclusiveMinimum":0,"description":"Resolve the latest build for this PR number."},"buildId":{"type":"string","format":"uuid","description":"Resolve this exact build id."},"diffResultId":{"type":"string","format":"uuid","description":"The diff result to comment on (from get_build/get_diff)."},"body":{"type":"string","minLength":1,"maxLength":4000,"description":"The comment text."},"anchor":{"anyOf":[{"anyOf":[{"type":"object","properties":{"type":{"type":"string","const":"point"},"x":{"type":"number","minimum":0,"maximum":1},"y":{"$ref":"#/properties/anchor/anyOf/0/anyOf/0/properties/x"}},"required":["type","x","y"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"rect"},"x":{"$ref":"#/properties/anchor/anyOf/0/anyOf/0/properties/x"},"y":{"$ref":"#/properties/anchor/anyOf/0/anyOf/0/properties/x"},"w":{"type":"number","exclusiveMinimum":0,"maximum":1},"h":{"type":"number","exclusiveMinimum":0,"maximum":1}},"required":["type","x","y","w","h"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"path"},"points":{"type":"array","items":{"type":"object","properties":{"x":{"$ref":"#/properties/anchor/anyOf/0/anyOf/0/properties/x"},"y":{"$ref":"#/properties/anchor/anyOf/0/anyOf/0/properties/x"}},"required":["x","y"],"additionalProperties":false},"minItems":2,"maxItems":512},"closed":{"type":"boolean"}},"required":["type","points","closed"],"additionalProperties":false}]},{"type":"null"}],"description":"Where on the candidate image to pin it (0..1 normalized): omit/null = whole diff; {type:'point',x,y}; {type:'rect',x,y,w,h}; {type:'path',points,closed}. Ignored on a reply."},"side":{"type":"string","enum":["before","after"],"description":"Which pane: 'after' (candidate, default) or 'before' (baseline). Ignored on a reply."},"parentId":{"type":"string","format":"uuid","description":"Reply to this thread ROOT comment's id (from list_comments) instead of starting a new thread."}},"required":["diffResultId","body"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"render_diff_image","description":"Fetch 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).","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"diffResultId":{"type":"string","format":"uuid","description":"A CHANGED story's diff result id (from get_build/get_diff); pair with `which`."},"which":{"type":"string","enum":["baseline","candidate","diff","before_after"],"description":"For the diffResultId form: baseline|candidate|diff (one triptych image, default candidate), or before_after (baseline+candidate side by side, cropped to the change - one crop per changed region, stacked, when the change spans several places). Ignored for the storyId form."},"commitSha":{"type":"string","minLength":1,"description":"Resolve the build for this git commit SHA."},"prNumber":{"type":"integer","exclusiveMinimum":0,"description":"Resolve the latest build for this PR number."},"buildId":{"type":"string","format":"uuid","description":"Resolve this exact build id."},"storyId":{"type":"string","description":"With a build selector: fetch THIS story's current image (works for unchanged stories)."},"pxPagination":{"type":"object","properties":{"offset":{"type":"integer","minimum":0,"description":"Top y (device px) of the slice to return."},"height":{"type":"integer","exclusiveMinimum":0,"default":500,"description":"Slice height in device px (default 500)."}},"required":["offset"],"additionalProperties":false,"description":"Paginate a TALL image slice by slice instead of one unreadable image: return the `height` device px starting at y=`offset`, so a 5000px page is reviewed in readable slices. Omit for the whole image. Ignored for the before_after form (already cropped to the change)."}},"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"resolve_comment","description":"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.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"commentId":{"type":"string","description":"The thread root comment id (from list_comments)."},"resolved":{"type":"boolean","description":"true to resolve the thread, false to reopen it."}},"required":["commentId","resolved"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"review_diff","description":"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.","write_action":false,"price_micros":0,"input_schema":{"type":"object","properties":{"diffResultId":{"type":"string","format":"uuid","description":"The diff result id from get_build or get_diff."},"decision":{"type":"string","enum":["accept","deny","ignore"],"description":"'accept' advances the baseline; 'deny' records a rejection; 'ignore' excludes the story from the gate."}},"required":["diffResultId","decision"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}},{"name":"update_comment","description":"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.","write_action":true,"price_micros":0,"input_schema":{"type":"object","properties":{"commentId":{"type":"string","description":"The comment id to edit (from list_comments)."},"body":{"type":"string","minLength":1,"maxLength":4000,"description":"The new comment text."}},"required":["commentId","body"],"additionalProperties":false,"$schema":"http://json-schema.org/draft-07/schema#"}}],"scan":{"score":79,"grade":"B","scanned_at":"2026-09-20T16:16:31.579Z","report":{"scannerVersion":"0.1.9","scannedAt":"2026-09-20T16:16:31.539Z","components":{"code":{"score":-1,"max":25,"notes":["remote-only server, no package to scan"]},"reliability":{"score":17,"max":20,"notes":["remote reachable in 2202ms"]},"poisoning":{"score":15,"max":15,"notes":["14 tool descriptions checked"]},"auth":{"score":8,"max":15,"notes":["API key sent as a header"]},"maintenance":{"score":15,"max":15,"notes":["last push 2 days ago"]},"identity":{"score":4,"max":10,"notes":["namespace and repository owner differ"]}},"findings":[],"inputs":{"probes":[{"url":"https://uiverify.ai/api/mcp","reachable":true,"authRequired":false,"latencyMs":2202,"serverInfo":{"name":"uiverify","version":"0.1.0"}}],"packages":[],"repo":{"found":true,"owner":"uiverify","repo":"uiverify","archived":false,"pushedAt":"2026-09-18T18:28:10Z","stars":22,"forks":1,"openIssues":1,"ownerType":"Organization","ownerAvatarUrl":"https://avatars.githubusercontent.com/u/301905904?v=4","ownerCreatedAt":"2026-07-09T22:12:48Z","license":"MIT"},"icon":{"url":"https://avatars.githubusercontent.com/u/301905904?v=4&s=128","source":"github"},"presence":{"stars":22,"forks":1,"downloadsWeek":null,"license":"MIT","lastPushAt":"2026-09-18T18:28:10.000Z","score":36}}}},"grade_history":[],"reviews":[]}