UI Verify
All docs
Reference5 min readUpdated

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:

bash
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.

FieldResolves to
commitShaThe latest build for that git commit
prNumberThe latest build for that pull request number
buildIdThat 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_build and get_pr_changeset return the first 25 of each list, plus a NextCursor field per list (changedNextCursor, failedNextCursor, newNextCursor, and so on). A non-null cursor means there is more.
  • list_build_stories and list_pr_stories page the rest: pass nextCursor back as cursor. limit defaults to 25, max 100. A nextCursor of null means the last page.
  • list_builds takes a limit instead: default 20, max 100, newest first.
  • render_diff_image paginates a tall image by pixels: pxPagination: { offset, height } returns a slice height device pixels tall (default 500) starting at offset.

Read tools

Read tools never change anything and are annotated read-only, so a client may run them without a confirmation prompt.

ToolKey argumentsWhat it does
list_buildsbranch?, 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_buildselectorTriage 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_storiesselector, status (changed, unchanged, failed), cursor?, limit?Page through one status. unchanged lists stories identical to their baseline, once the build has settled.
get_pr_changesetselectorWhat 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_storiesselector, kind (new, changed, removed), cursor?, limit?Page through one kind of the PR changeset.
get_diffselector, 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_imagediffResultId + 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.

ToolKey argumentsWhat it does
review_diffdiffResultId, 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_buildselectorAccept 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.

ToolKey argumentsWhat it does
list_commentsselectorEvery comment on the build's changed stories: its diff, author (a person or an agent), body, anchor, and whether its thread is resolved.
post_commentselector, 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_commentcommentId, bodyReplace a comment's text. Agent-authored comments only.
resolve_commentcommentId, resolvedResolve (true) or reopen (false) a thread. Pass the thread's root comment id.
delete_commentcommentIdDelete 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:

  1. Find the build with list_builds, or select it directly by the commit SHA or PR number from CI.
  2. Call get_build for the verdict and the changed stories, likely regressions first when AI review ran. Page further with list_build_stories.
  3. Read a story's verdict and reasoning with get_diff, then look at what moved with render_diff_image and which: "before_after".
  4. If the story has an open comment, read it with list_comments, address it, and close it with resolve_comment.
  5. Accept the intended change or deny the regression with review_diff, or use accept_build once every change is intended.
  6. Optionally, check get_pr_changeset to confirm the whole PR did only what it meant to.
The triage visual changes skill packages this loop into one command your agent can run.

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