Docs
Let your AI assistant read Happo's visual and accessibility diffs, fix what it didn't mean to change, and accept or reject the rest. It works with Claude, ChatGPT, Cursor and any other MCP-aware client.
Your assistant already has your code and knows what each change was meant to do, so it brings the context and Happo brings the diffs. Happo never needs access to your repository.
Paste it where your client asks for one. It opens your browser to sign in to Happo and pick the account the assistant may use: no API token to copy.
On Team and Enterprise plans, an owner may need to allow the connector first. You can also add Happo under Settings → Connectors → Add custom connector with the server URL above.
~/.cursor/mcp.json, for every project, or to .cursor/mcp.json at a repository's root, to share it with your team (Cursor's docs):Add a remote MCP server with the server URL above. Happo speaks the Streamable HTTP transport and signs clients in with OAuth 2.1: a client finds the sign-in endpoints at /.well-known/oauth-protected-resource and opens your browser, so there is no token to configure.
Once you're connected, ask in your own words. A few to start with (click one to copy it):
The assistant picks these tools itself as it works through your request. This list comes from the server, so it is always the tools it offers today.
Find comparisons and read what changed in them. These change nothing.
get_accountsList the Happo accounts this connection is authorized to act on.
When more than one account is returned, every other tool requires the account argument set to one of these account ids.
list_comparisons_for_shaList all Happo comparisons that include the given commit SHA as either the "before" or "after" report.
Spans all projects on the account by default; pass project to filter. Returns comparison metadata you can feed into get_comparison_details, accept_comparison, etc.
sha stringrequiredproject stringget_comparison_detailsGet the diffs, added and deleted snapshots of a comparison between two reports, with the signed image URLs to look at and the ids the review tools take.
Use this to understand what visual changes are in a PR. reviewOrder lists them the way the comparison page does: most important first, with targets and variants that made the same change folded together so one inspection stands for many. Where Happo measured a diff, it also says how much changed and whether it is anti-aliasing noise. A large comparison comes in pages of whole reviewOrder rows: when nextOffset is not null, call again with offset set to it for the next. Ignored diffs are only counted (counts.ignored, ignoredBy) unless includeIgnoredDiffs is set, apart from the first flakes people reported (reportedFlakes). Read every page before accept_comparison, which accepts every diff. The first page of a comparison that takes more than one has an overview of all of it, which often answers what it holds without the rest. Heavy deep-comparison work is skipped — this returns the previously-computed comparison result.
sha1 stringrequiredsha2 stringrequiredproject stringoffset integernextOffset, a place in the comparison rather than a count, so verdicts cast between pages skip nothing. Omit for the first page.limit integerincludeIgnoredDiffs booleanignoredDiffs), after the rows to review and paged with them, each with who ignored it and why. Leave it out to review a comparison: an ignored diff needs no verdict. Set it when the user asks about ignored diffs or flakes.get_diff_measurementsWhere the given diffs of a comparison changed, as Happo measured them.
regions and contentShifts place each change in the before and after images, in their own pixels, ready to crop to; beside them are how much changed and the size each image decoded to. With raw, everything stored follows instead: every changed rectangle with its pixel hashes and structural difference, the histogram of color distances, the row alignment between the two images and the settings it measured under. get_comparison_details summarizes these; ask for them when the summary is not enough to decide.
sha1 stringrequiredsha2 stringrequiredpairs array of objectrequiredbefore.id and after.id (ignored diffs too).raw booleanproject stringget_render_logsRead the render logs: what Happo logged while rendering the snapshots of one report (one commit SHA's run): pages loading, console messages, failed requests, images and fonts that timed out or were still loading right before the screenshot, retries and errors.
Use it to find out why a snapshot rendered wrong or differently between runs. A report is rendered by several snap requests (one per target and chunk), each with its own log, and a whole report can be hundreds of thousands of lines, so narrow it: snapshotId returns only the lines for that snapshot, query only matching lines, minLevel only warnings or errors. Snapshots are rendered one after another, and with Storybook many share one page, so a snapshot's lines run from where the one before it finished to its own Processed <component>, <variant> in <browser> (<timings>) line: the name is at the end, with how many milliseconds the render (r), the wait for the page to settle (w) and the screenshot (s) took. What loading the page logged (scripts, stylesheets, fonts) comes before the first snapshot and is in no snapshot's lines: read a snap request's log from its start with snapRequestIds for that. With snapshotId, query or minLevel, snap requests that matched nothing are only named, in unmatchedSnapRequestIds. Read-only. Logs are kept for a limited time, so an old report's may be gone.
sha stringrequiredget_comparison_details, sha2 rendered the "after" snapshot and sha1 the "before".snapshotId stringid from get_comparison_details. Returns only the lines logged while rendering that component and variant, from the logs of that snapshot's target. The run is searched by those names, so the snapshot of another report shows how this one rendered the same component and variant.query stringcontextLines around each.minLevel "info" | "warn" | "error"contextLines around each. Most lines are info; a warning is something the render had to work around.contextLines integerquery or minLevel matched. Defaults to 2.snapRequestIds array of integerid an earlier call listed.offset integernextOffset to continue.maxLines integerproject stringAccept, reject or report a flake. Each is recorded against you, the same as clicking the button on the compare page.
accept_diffAccept one diff, added snapshot or deleted snapshot in a Happo comparison, or several with pairs: the change is intended.
Recorded against the snapshot pair, so it also counts in later comparisons with the same change. Once every diff, added and deleted snapshot is accepted (or reported as a flake), the comparison is accepted too, unless render errors, new accessibility violations or pages that start to scroll sideways block it, which the response lists in acceptBlockedBy. When render errors block it, a diff or added snapshot that failed to render cannot be accepted. Returns the comparison's resulting status. Only on accounts where you have per-diff review: the new compare page, by the account or your own opt-in.
sha1 stringrequiredsha2 stringrequiredbeforeSnapshotId stringbefore.id, or a deleted snapshot's id. Omit for an added snapshot.afterSnapshotId stringafter.id, or an added snapshot's id. Omit for a deleted snapshot.pairs array of objectget_comparison_details' reviewOrder with its sameAs targets and sameChange rows, which the comparison page decides with one verdict. All or none are recorded.project stringreject_diffReject one diff, added snapshot or deleted snapshot in a Happo comparison, or several with pairs: the change is unintended.
Rejecting any one of them rejects the whole comparison. Returns the comparison's resulting status. Pass note to say why, which reviewers see beside the diff. Only on accounts where you have per-diff review: the new compare page, by the account or your own opt-in.
sha1 stringrequiredsha2 stringrequiredbeforeSnapshotId stringbefore.id, or a deleted snapshot's id. Omit for an added snapshot.afterSnapshotId stringafter.id, or an added snapshot's id. Omit for a deleted snapshot.pairs array of objectget_comparison_details' reviewOrder with its sameAs targets and sameChange rows, which the comparison page decides with one verdict. All or none are recorded.project stringnote stringreport_flakeMark a specific diff as a flake/spurious.
Pass the snapshot IDs from get_comparison_details (the before.id and after.id of a diff). This both ignores the diff and records a Flake row attributed to the connected user. On an account that only lets selected users review, the connected user has to be one of them.
sha1 stringrequiredsha2 stringrequiredsnapshot1Id stringrequiredbefore.id).snapshot2Id stringrequiredafter.id).project stringaccept_comparisonAccept (mark as success) the Happo comparison between two reports.
Its earlier name, approve_comparison, still works.
Use this to resolve a "needs review" comparison after you have inspected the diffs and decided the changes are intended. It accepts every diff, so when get_comparison_details came in pages, read them all first.
sha1 stringrequiredsha2 stringrequiredproject stringreject_comparisonReject (mark as failure) the Happo comparison between two reports.
Use this when the changes are unintended.
sha1 stringrequiredsha2 stringrequiredproject stringEvery tool that takes arguments also takes these, so they're listed here once.
account integerget_accounts first to list them.When you authorize a client, you pick the Happo account the connection applies to. The assistant has your permissions on that account: it can read everything you can, and what it accepts or rejects is recorded against you.
Revoke a connection under Connected applications on your account's API tokens page.