UI Verify MCP server: tool reference
The UI Verify MCP server lets a coding agent list builds, read diffs, see the pixels, comment, and accept baselines, authenticated with your project API key.
Every tool is confined to one project: the one whose key the client connects with. This page lists each tool with its key arguments and what it returns, for wiring the server into Claude Code, Cursor, or any MCP client. For the review workflow itself, see Triage visual changes from your coding agent.
Endpoint and transport
The UI Verify MCP endpoint is https://uiverify.ai/api/mcp. It uses the Streamable HTTP transport and is stateless: each call stands on its own, with no session to keep alive. SSE is not offered.
Authentication with a project API key
The server authenticates with your project API key (uv_proj_...), sent as a Bearer token in the Authorization header. It is the same key your CI uses for uiverify upload. In Claude Code:
claude mcp add --scope project --transport http uiverify https://uiverify.ai/api/mcp \
--header 'Authorization: Bearer ${UIVERIFY_API_KEY}'The key is referenced as the UIVERIFY_API_KEY env var, single-quoted so your shell does not expand it when you add the server. Claude Code expands it at runtime, so the committed .mcp.json never holds the secret. Your project setup page shows the same command, and any other MCP client takes the same URL and header. Restart the agent session after adding it so the tools load.
Does listing the tools need an API key?
No. The initialize handshake and tools/list answer without a key, so any client or MCP directory can discover the tool names and schemas. Calling a tool does need the key: without one, the call returns an error asking you to connect with your uv_proj_ key, and no data. Every read and write is scoped to the key's project, so a build from another project reads as not found.
Build selector: commitSha, prNumber, or buildId
A build selector is how most tools choose the build to act on. Pass exactly one of the three fields; passing none or more than one returns an error.
| Field | Resolves to |
|---|---|
commitSha | The latest build for that git commit |
prNumber | The latest build for that pull request number |
buildId | That exact build |
list_builds takes no selector, since it is how you find a build. Tools that act on one story or one comment take that item's id instead: diffResultId for review_diff, and commentId for update_comment, resolve_comment, and delete_comment.
Pagination and page sizes
Pagination keeps a large build from flooding the agent's context: story lists come back a page at a time with an opaque cursor.
get_buildandget_pr_changesetreturn the first 25 of each list, plus aNextCursorfield per list (changedNextCursor,failedNextCursor,newNextCursor, and so on). A non-null cursor means there is more.list_build_storiesandlist_pr_storiespage the rest: passnextCursorback ascursor.limitdefaults to 25, max 100. AnextCursorofnullmeans the last page.list_buildstakes alimitinstead: default 20, max 100, newest first.render_diff_imagepaginates a tall image by pixels:pxPagination: { offset, height }returns a sliceheightdevice pixels tall (default 500) starting atoffset.
Read tools
Read tools never change anything and are annotated read-only, so a client may run them without a confirmation prompt.
| Tool | Key arguments | What it does |
|---|---|---|
list_builds | branch?, status?, limit? | Recent builds, newest first, each with its gate status (pending, running, passed, changed, failed or blocked). The way to find a build. The status filter matches the build's raw status, which can also be preflight while a build is starting up. |
get_build | selector | Triage one build: the verdict, counts (total, changed, failed, unchanged), the first page of changed and failed stories with the AI verdict when AI review ran, and a review-comment tally. |
list_build_stories | selector, status (changed, unchanged, failed), cursor?, limit? | Page through one status. unchanged lists stories identical to their baseline, once the build has settled. |
get_pr_changeset | selector | What the whole PR does to the UI vs its base branch: counts and the first page of new, changed, and removed stories. See This PR vs base. |
list_pr_stories | selector, kind (new, changed, removed), cursor?, limit? | Page through one kind of the PR changeset. |
get_diff | selector, storyId? | Diff metrics, the AI judge's verdict and reasoning, and time-limited URLs for the baseline, candidate, and diff PNGs. Defaults to the changed stories. |
render_diff_image | diffResultId + which?, or selector + storyId; pxPagination? | The image itself as inline pixels for a vision model. which is baseline, candidate (default), diff, or before_after. |
before_after puts the baseline and candidate side by side, cropped to the changed region, with one crop per region when a story changed in several places. The storyId form returns any story's current image, including an unchanged one. Inline images need a client that renders image content; in a shell script, use get_diff's URLs instead.
Review tools
Review tools record the same accept, deny, and ignore decisions as the dashboard, attributed to your project key.
| Tool | Key arguments | What it does |
|---|---|---|
review_diff | diffResultId, decision (accept, deny, ignore) | Review one story. accept makes the candidate its new baseline on the branch, deny records a rejection without moving the baseline, ignore keeps the story out of the gate on future builds. |
accept_build | selector | Accept every changed story in the build at once, including ones denied earlier. Failed stories are unaffected. Returns the updated triage. |
While a story has an unresolved review comment, review_diff refuses to accept or ignore it, and accept_build accepts nothing and names the stories with open notes. Deny always works. See Collaborative visual review.
Comment tools
Comment tools read and write the review threads on a build's diffs. They are available when review comments are enabled for your team; otherwise a call returns an error saying so. A comment written over MCP is authored as the agent.
| Tool | Key arguments | What it does |
|---|---|---|
list_comments | selector | Every comment on the build's changed stories: its diff, author (a person or an agent), body, anchor, and whether its thread is resolved. |
post_comment | selector, diffResultId, body, anchor?, side?, parentId? | Start a thread on a diff, or reply to one with parentId. A new thread goes on the latest build on the branch; replies work on any. |
update_comment | commentId, body | Replace a comment's text. Agent-authored comments only. |
resolve_comment | commentId, resolved | Resolve (true) or reopen (false) a thread. Pass the thread's root comment id. |
delete_comment | commentId | Delete one comment. Agent-authored comments only. |
A body is 1 to 4,000 characters. An anchor pins the comment on the image in coordinates normalized 0 to 1: omit it for the whole diff, or pass {type: 'point', x, y}, {type: 'rect', x, y, w, h}, or {type: 'path', points, closed}. side picks the pane: after (the candidate, default) or before (the baseline). A reply inherits its thread's side and carries no anchor.
Tool responses
Tool responses are JSON, returned both as a text block and as structuredContent that matches the tool's declared output schema. render_diff_image is the exception: it returns an image block, preceded by a text note when the story has open comment threads. An expected refusal, such as an unknown build or an invalid cursor, comes back as a tool error with a message the agent can act on.
Typical agent loop
A typical agent loop goes from a list of builds to a decision on each changed story:
- Find the build with
list_builds, or select it directly by the commit SHA or PR number from CI. - Call
get_buildfor the verdict and the changed stories, likely regressions first when AI review ran. Page further withlist_build_stories. - Read a story's verdict and reasoning with
get_diff, then look at what moved withrender_diff_imageandwhich: "before_after". - If the story has an open comment, read it with
list_comments, address it, and close it withresolve_comment. - Accept the intended change or deny the regression with
review_diff, or useaccept_buildonce every change is intended. - Optionally, check
get_pr_changesetto confirm the whole PR did only what it meant to.
Triage a build from your agent
Bucket real regressions vs noise and accept baselines, over MCP.
Visual testing MCP: let your agent triage the diffs
Backend agents self-correct from logs and failing tests. UI agents are blind - they say 'looks great' and ship the break. Visual testing over MCP gives the agent eyes on the actual diff.
Visual testing for agents
UI Verify captures your UI on every pull request and an AI judge tells an intended change from a real regression. See how it works.
Get started