WebMCP review session
Three screens went to build and came back different. Sweeping all of them, ranking them and drafting the ticket is mechanical work, and this page hands that to your agent as WebMCP tools. What is left is the part that needs a person: looking at the two frames and saying whether a difference is a bug or a decision somebody already made.
The agent cannot set a status. It can put a screen in front of you, argue for a finding, and record what you say, with a reason, which is why the number moved. Everything it does shows up on this page as it happens, and everything you do is readable by it.
This repo is public and ships no API key, so the three screen pairs below are original mockups generated by scripts/make-samples.mjs, not anyone’s real product, with the divergences planted on purpose, and their findings recorded on 2026-08-25 and checked into src/lib/samples/data.ts. No vision model runs in this session.
Everything downstream of the model is live: the scoring arithmetic, the adjudication, the rescore that follows a dismissal, and the ticket. To run the model against your own screenshots, use the uploader on the home page with an API key set.
3
Average 78/100
12
Findings nobody has judged yet
0
Confirmed defects
0
Intentional, out of the score
Design frame at 1x, build captured at 2x · model confidence: high
Needs rework
as recorded, nothing dismissed yet
Several major divergences, or something structural is wrong.


The design places a dashed promo-code row between the line items and the totals block. The build goes straight from the last line item to the subtotal, so there is no way to enter a code on this screen.
The primary action reads as a neutral slate rather than the green used everywhere else in the flow. On a checkout screen the primary action is the one element that should be unmistakably branded.
The gap between line items is visibly wider, which pushes the totals block down and leaves a large empty band above the pay button.
The total is the number the customer checks before paying, and it is set noticeably lighter than the design, so it no longer outweighs the subtotal rows above it.
Judgement call Weight differences can be a font-loading artifact in a capture rather than a code difference. Worth a human eye before it becomes a ticket.
The reassurance line under the pay button is centred in the design and left aligned in the build, so it no longer reads as attached to the button.
Dismissing removes a finding from the score. Every status on this list is visible to the agent through get_drift_report, and every status the agent sets is visible here.
weight 22 · 1C 0M 0m
weight 18 · 0C 1M 0m
weight 26 · 0C 0M 1m
weight 20 · 0C 0M 1m
weight 14 · 0C 0M 1m
Ask the agent to file_ticket once you have judged the findings, or press the button in the console below. It is composed from what survived, so dismissed findings never reach whoever picks the ticket up.
No WebMCP host was detected in this browser, on either document.modelContext or navigator.modelContext, so there is no agent to drive the page. These buttons call the exact same tool functions an agent would, through the same code path, so the whole loop is visible anyway.
dismiss_finding without a reason is rejected on purpose. Clear the id and try accept_finding with a bad id to see the error an agent gets back.
Tool responses appear here, exactly as an agent receives them.
Nothing yet. Every tool call and every judgement lands here, tagged with who made it.
Registered through registerTool on whichever host global carries it, document.modelContext or navigator.modelContext (Chrome 146+), with a batch provideContext fallback for hosts that expose that shape instead. Source: src/webmcp/tools.ts.
List the design/implementation screen pairs loaded in this review session, each with its current score and how many findings are still unreviewed. Call this first.
Get the scored drift findings for one screen pair and put that pair on the reviewer's screen, design beside build. Returns every finding with an id, a rubric category, a severity and its current adjudication status.
Rank every loaded screen pair by drift severity, worst first, so the review starts where it matters. Use this to decide what to show the reviewer next.
Record that the reviewer agrees a finding is a real defect. It stays in the score and goes into the ticket. Only call this after the human has actually said so.
Record that the reviewer judged a finding to be intentional or not worth filing. It leaves the ticket and the score is recomputed without it. A reason is required and is shown on the page beside the finding.
Draft a paste-ready ticket for one screen from the findings still standing after adjudication, and show it on the page. Optionally pass a subset of finding ids to include.
Totals for the whole review session: screens checked, findings open, accepted and dismissed, average score and the worst screen.