mcp-review
OfficialClick on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-reviewReview https://preview.example.com/pricing for design issues and recheck after fixes."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
An MCP server that gives a coding agent eyes on the UI it just changed: submit a preview URL, get findings with route, viewport, element ref and a suggested fix, apply them yourself, then ask the server to recheck. It judges and verifies; it never edits code, drives a browser, or opens a pull request — the server is the eyes, the agent is the hands. Everything runs offline with no credentials, and with nothing configured the judgments come from a golden fixture that says so in every payload; one clone and one environment variable swap in a real critique of a real page.
Quickstart
Node 24+ and pnpm 9.15.0 (corepack enable installs pnpm from the packageManager field). No API key, no database, no Docker; pnpm install needs the npm registry once, and after that nothing here opens a connection.
git clone https://github.com/apatureai/bastion.git
cd bastion
corepack enable
pnpm install --frozen-lockfile
pnpm build
pnpm demopnpm demo is a real MCP client. It spawns the server as a child process over stdio, completes a handshake, submits a review, reads it back four ways, acts on a finding, rechecks it, and is denied on an unauthorized host — the nine steps shown in the hero above. It ends:
[9] design_review https://evil.example.org/ (SSRF boundary)
rejected: DOMAIN_UNVERIFIED (next_action: verify_domain)
Done. 3 findings, 3 recheck outcomes.
Open out/panel.html in a browser to see the review panel.Success looks like nine numbered steps, 3 findings, 3 recheck outcomes, and two new files: out/review.json (the agent-facing Critique) and out/panel.html (the self-contained review panel).
open out/panel.html # macOS; use xdg-open on LinuxThe server still identifies itself on the wire as
apature-mcp-review. That name is part of the MCP handshake and any client configuration that already references it, so the repository rename tobastiondeliberately left it alone.
If pnpm demo reports Cannot find module, pnpm build has not been run. If step 2 comes back DNS_TARGET_PROHIBITED instead of a job, something changed LOCAL_RESOLVED_ADDRESS in packages/mcp-server/src/local-server.ts to a non-public address, and that rejection is the SSRF guard working.
Related MCP server: vibe-annotations
What you get
pnpm demo reviews https://preview.example.com/pricing and writes two files. out/review.json is the Critique a coding agent reads: a grade, a findings[] array where each entry carries a dimension, severity, route, viewport, element_ref and a suggestion fix string, plus two envelopes an agent must check before trusting any of that — provenance and coverage. out/panel.html is the same review as a self-contained HTML panel: no scripts, no external requests, evidence embedded as data: URIs. The job_* and rev_* ids are freshly generated, so yours differ from the hero's.
With nothing configured the findings are a golden fixture describing a fictional pricing page, not a judgment of the URL you passed — and the payload says so rather than relying on the startup banner, because the consumer is usually an agent that never sees the banner. The full result contract covers grounding, the model-free measurements block, and how every payload an agent reads — the recheck, the panel action, each finding, each content block — carries the same marker.
Provenance: did anything judge this page?
Every Critique carries a provenance object, on every backend including the offline fixture path, so an agent that never sees the terminal can answer "which engine ran" from the payload alone:
"grade": "unjudged",
"confidence": null,
"provenance": { "model_backed": false, "source": "fixture", "engine": "bastion-fixture", "model": null }The rule an agent codes against: trust the result only when provenance.model_backed === true and coverage.state is not "nothing". When model_backed is false — the fixture engine, or verdict run with --model mock/--model canned — the grade is the literal "unjudged", confidence is null, the narrative says no model judged the page instead of describing one, and every finding carries "unjudged": true. When it is true, the engine's grade, narrative and findings pass through untouched and provenance.model names the judge. A remote verdict deployment reports null: a real judgment may be behind it, but this process cannot see how that deployment is configured and does not claim to.
Coverage: what did it actually look at?
provenance answers whether a model judged the page; it does not answer what the model judged, and those come apart. Verdict's triage can conclude a deep review is needed and then name no route to run it on: a model really was called (model_backed truthfully true), yet no page was judged, and a result with no surviving findings grades ship by construction. So every Critique also carries coverage:
"grade": "nothing_reviewed",
"coverage": { "state": "nothing", "routes_requested": ["/", "/pricing"], "routes_reviewed": [], "routes_skipped": ["/", "/pricing"] }state is full (nothing suppressed), partial (a real verdict about a smaller surface; routes_skipped names what it missed), nothing (the grade becomes "nothing_reviewed" and every finding is marked unjudged), or unstated (the engine reported no coverage — never read as "everything was reviewed"). nothing_reviewed wins over unjudged when both apply, and both facts stay in the payload. This is the same rule and vocabulary apatureai/gate uses for its Check Run, so the two surfaces cannot tell different stories about one run.
Usage
Tool | Metered | What it does |
| yes | Submit an async review of an authorized HTTPS preview (routes, viewports, |
| no | Poll job status or read the result in one of five views. |
| yes | Re-judge 1 to 20 findings from a completed review after the agent changed the UI. Rejects a host change or an unchanged target. Runs against the fixture engine only, where every outcome comes back |
| no | Best-effort cancel of a queued or running job; requires the |
| no | Route a review-panel interaction: return a grounded finding's fix for the agent, or the refs to re-verify. Returns |
MCP annotations are set from the truth: only design_review_get and design_review_panel_action carry readOnlyHint: true, because submit and recheck create metered jobs and cancel terminates one.
design_review_get views
| Returns |
| The job envelope only. No result body, so it stays cheap while a job is still running. |
| Job plus the full |
| Same body as |
| Job plus the |
| Job, |
The eyes-not-hands boundary, in code
design_review_panel_action is where the product boundary is easiest to violate and easiest to test. When a reviewer clicks "apply fix" on a finding, the server reads the completed Critique, projects it into fix items (reviewFixItemsFromCritique) where a finding is grounded only if it is localizable (element_ref) and carries a concrete repair constraint (suggestion), and runs a pure reducer (handlePanelAction):
a grounded finding comes back
{ "type": "fix", "fix": "..." }, and that fix is for the host to hand to the coding agent;an advisory finding comes back
{ "type": "human_only" }, never an auto-fix;a finding from a review nothing judged comes back
{ "type": "unjudged" }with no fix string at all, because on that path the instruction is fixture text and handing fixture text to a coding agent is precisely the failure this boundary exists to prevent.
"Resolved" is a recheck verdict the service earns, not a status the panel can set.
Connect your own MCP client
The local server speaks MCP over stdio — what Claude Code, Cursor, Codex, and VS Code use for a local server. pnpm demo spawns exactly this command and completes a real handshake against it:
{
"mcpServers": {
"apature-review-local": {
"command": "node",
"args": ["/absolute/path/to/bastion/packages/mcp-server/dist/local-stdio.js"]
}
}
}The only host the local server authorizes is preview.example.com; every other host is rejected as DOMAIN_UNVERIFIED. Add your own hosts and a critique backend through the environment, with no code change and no rebuild:
{
"mcpServers": {
"apature-review": {
"command": "node",
"args": ["/absolute/path/to/bastion/packages/mcp-server/dist/local-stdio.js"],
"env": {
"BASTION_ALLOWED_HOSTS": "preview.mycompany.com",
"VERDICT_CLI": "/absolute/path/to/verdict",
"MODEL_BASE_URL": "https://your-openai-compatible-endpoint/v1",
"MODEL_API_KEY": "..."
}
}
}
}Getting real judgments
With nothing configured the findings are a fixture about a fictional pricing page. This replaces them with a real critique of a real page — no credentials from this project, no database, no hosted service. The backend is apatureai/verdict, public and MIT: it launches headless Chromium, captures each route at each viewport, measures the DOM, critiques the render against your repository's own design system, deletes every finding it cannot point at, and writes the EngineReviewResult that packages/mcp-types/src/engine.ts declares and this server consumes. Connecting them is configuration, not code.
1. Build verdict
git clone https://github.com/apatureai/verdict.git
cd verdict && corepack enable && pnpm install --frozen-lockfile && pnpm build
pnpm browser:install # Chromium for playwright-core, roughly 275 MB downloaded2. Point bastion at it
export VERDICT_CLI=/absolute/path/to/verdict
export MODEL_BASE_URL=https://your-openai-compatible-endpoint/v1
export MODEL_API_KEY=<your-key>VERDICT_CLI selects the backend; MODEL_BASE_URL and MODEL_API_KEY are verdict's own variables, passed straight through, so any OpenAI-compatible chat-completions endpoint that accepts images works. Neither half is optional: a key with no base URL, or an explicit VERDICT_MODEL=live with no key, is a startup error rather than a silent fallback to the mock — verdict would otherwise answer a live request with its mock client and report model_backed: true anyway.
3. Review a URL
pnpm review https://preview.mycompany.com/pricing --routes /pricing --viewports desktoppnpm review is the same MCP client pnpm demo uses, pointed at a target you name on the command line (which authorizes that host for the run, and says so before it starts). With a key set, verdict runs --model live and a model looks at your screenshots; without one it runs --model canned, which captures and measures your page for real but judges nothing, and announces that loudly. The per-run artifact directory under out/verdict/ keeps the screenshots, the DOM geometry map, the measured facts, and the resolved system prompt, so a finding can be checked against what the model was actually shown.
The SSRF boundary makes one narrow exception: a loopback host you name explicitly (localhost, 127.0.0.0/8, ::1) is your own dev server, so it may be plain http. The exception is keyed on the literal host, never on where a name resolves, so a public name pointed at loopback is still refused before verdict is even started — DNS-rebind protection:
$ pnpm review https://localtest.me/
rejected: DNS_TARGET_PROHIBITED
host localtest.me resolves to a prohibited (loopback) addressA rejected target is the boundary working, not a crash: pnpm review prints the code and reason and exits 1 (it exits 2 only on a usage or engine-configuration error, and 0 on a completed review), so an agent loop can tell a refused target apart from a bug.
What each mode gives you
fixture (default) | verdict CLI, no key | verdict CLI, live model | |
Configuration | none |
|
|
Screenshots of your page | no | yes | yes |
DOM measurements of your page | no | yes | yes |
Findings about your page | no | no | yes |
Grade in the payload |
|
| the engine's grade |
|
|
|
|
Cost | none | none | your endpoint's per-call price |
| yes, but every outcome is | no, see below | no, see below |
Every critique-backend variable and the honest list of what is not wired yet — including why design_recheck does not work against either verdict backend — are in docs/configuration.md.
Configuration
None of the variables below are needed by the local server, the quickstart, or the test suite — they configure the Streamable HTTP edge. Dockerfile builds the workspace and runs packages/mcp-server/dist/boot.js, the production composition root: Streamable HTTP transport, bearer JWT verification against an issuer's JWKS, a Postgres application plane, and a signed client for the judgment engine. It fails closed with a readable message when configuration is missing, and it has no mock fallback — a server that answers with fixture judgments must be the local one, explicitly. Nobody operates a public instance, so directory/server.json declares no remotes.
Variable | Required | Default | Effect |
| yes (HTTP mode) | none | This server's public resource id, the expected token |
| yes (HTTP mode) | none | Comma-separated issuer URLs published in RFC 9728 discovery |
| yes (HTTP mode) | none | Issuer JWKS endpoint used to verify token signatures |
| yes (HTTP mode) | none | Expected token |
| yes (HTTP mode) | none | Postgres for durable jobs and the verified-target registry; migrations run at boot |
| yes (HTTP mode) | none | Judgment engine async job API origin |
| yes (HTTP mode) | none | Shared secret signing service-to-service calls |
| no |
| Listener port |
| no |
| MCP endpoint path |
| no | host of | Permitted |
| no |
| Request body ceiling; hard maximum 1 MiB |
| no |
| Body-read timeout |
| no |
| Concurrent authenticated requests per principal; hard maximum 64 |
| no | none | Test-only. When set, runs the Postgres migration test instead of skipping it |
The critique-backend variables (VERDICT_CLI, MODEL_BASE_URL, and the rest) are listed separately in docs/configuration.md; ENGINE_BASE_URL and ENGINE_HMAC_SECRET are shared by both surfaces.
Design notes
docs/result-contract.md — how grounding, the model-free
measurementsblock, and every agent-read payload carry the provenance marker.docs/design-notes.md — who this is for, why a design reviewer breaks the thin-MCP-wrapper assumptions, and the two independent version numbers.
docs/how-it-works.md — the production request path, what is real versus synthetic offline, and the repository map.
docs/configuration.md — the full critique-backend variable reference and what is not wired yet.
docs/roadmap.md — what works today and the known gaps, each with its seam.
Status
The local MCP server, all five tools and five views, target authorization and egress classification, job lifecycle and recheck semantics, the Streamable HTTP edge (OAuth 2.1 auth, per-client isolation) and the Postgres application plane all work today and are covered by the suite. A real critique backend runs over a local verdict checkout (pnpm review <url>, see Getting real judgments). The main open gaps are design_recheck against a verdict backend, real evidence images in the panel, and moving the recheck index and unit ledger into the store. Full detail and the seam for each is in docs/roadmap.md.
Contributing
CONTRIBUTING.md covers setup, the test and lint commands, and the conventions that matter (the eyes-not-hands boundary, the contract-tested tool catalog, golden fixtures); the roadmap items are the best place to start, and it is worth opening an issue first if a change is large.
Security
Report vulnerabilities privately through GitHub's private vulnerability reporting on the repository's Security tab. SECURITY.md describes supported versions, what a reporter can expect, and what to check before running this against a network you care about.
License
MIT — see LICENSE.
Available Tools
5 toolsdesign_recheckSubmit design recheckAIdempotent
Submit a metered recheck for findings from a completed review after the customer's agent changes the UI. This tool never edits code. Unchanged targets and exhausted recheck loops are rejected without running judgment. Check recheck.provenance before acting: when nothing judged the target every outcome is unjudged with a null confidence. Reuse client_request_id on retries.
| Name | Required | Description | Default |
|---|---|---|---|
| url | No | Optional URL on the same previously authorized host. A host change requires a new review. Plain http is accepted only for a loopback dev host (localhost, 127.0.0.0/8, ::1). | |
| review_id | Yes | ||
| finding_ids | Yes | Duplicates are accepted and canonicalized by the server, so uniqueness is not required. | |
| client_request_id | Yes | ||
| expected_revision | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| job | No | |
| error | No | Typed tool error, returned with isError: true instead of the result envelope. The full code and next_action vocabularies are in schemas/review-error.schema.json. |
| budget | No | |
| recheck | No | |
| schema_version | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations, it adds that the tool never edits code, is metered, rejects unchanged/exhausted targets without running judgment, and explains provenance behavior when nothing judged the target. It also reinforces idempotency by telling the agent to reuse client_request_id on retries. This is meaningful behavioral detail with no contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense but still readable, with four focused sentences. No sentence is wasted; each one adds either a behavioral guard, a retry hint, or a required precondition. It is slightly compressed but appropriate for the tool's complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool has 5 parameters, low schema coverage, and a nontrivial retry/recheck flow, the description leaves gaps around expected_revision semantics and how the provenance signal should be practically handled. The output schema helps, but the description alone is not fully sufficient for an agent to avoid stale or invalid recheck calls.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With only 40% schema description coverage, the description needed to compensate for undocumented parameters like expected_revision, review_id, and client_request_id. It only hints at client_request_id reuse and does not explain what expected_revision is for or how review_id relates to a prior review.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource: submitting a metered recheck for findings from a completed review. It further distinguishes the tool by stating it is for use after the customer's agent changes the UI, which separates it from the sibling design_review and related review tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It clearly states when to call the tool: after a completed review and UI changes. It also gives exclusions by noting unchanged targets and exhausted recheck loops are rejected, which informs an agent not to use it in those cases. It does not fully name alternative siblings, but the context is clear enough without explicit alternates.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
design_reviewSubmit design reviewAIdempotent
Submit an asynchronous, metered design review for a tenant-authorized HTTPS preview. This tool never edits code. Reuse client_request_id on retries, then poll design_review_get no faster than poll_after_ms.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Tenant-authorized remote preview URL. Plain http is accepted only for a loopback dev host (localhost, 127.0.0.0/8, ::1); everything else must be https. Userinfo and fragments are rejected. | |
| depth | No | deep | |
| routes | No | Duplicates are accepted and canonicalized by the server, so uniqueness is not required. | |
| viewports | No | Duplicates are accepted and canonicalized by the server, so uniqueness is not required. | |
| response_mode | No | compact | |
| client_request_id | Yes | Caller-generated idempotency key. Reuse it for retries of the same normalized request. | |
| expected_revision | No | Optional deploy ID, commit SHA, or revision marker expected at the target. |
Output Schema
| Name | Required | Description |
|---|---|---|
| job | No | |
| error | No | Typed tool error, returned with isError: true instead of the result envelope. The full code and next_action vocabularies are in schemas/review-error.schema.json. |
| budget | No | |
| schema_version | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false, openWorldHint=true, idempotentHint=true, and destructiveHint=false. The description adds 'asynchronous, metered,' which is not in the annotations, and reinforces the idempotency via 'Reuse client_request_id on retries.' It also states 'never edits code,' a behavioral guarantee. These add value beyond the annotations. It could mention what happens on failure, but the polling instruction implies a retry pattern. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences with no wasted words. The first sentence states purpose and a key behavioral fact (never edits code). The second gives actionable retry and polling guidance. Everything earns its place, and the most important information is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a submission tool with an output schema (which presumably contains poll_after_ms and review ID), the description covers the essential workflow: submit, retry with same ID, and poll with a specific tool. It doesn't explain how to cancel or recheck, but those are separate tools. The description is complete enough for an agent to successfully initiate a review without missing critical steps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 71% (5 of 7 parameters have descriptions). The description itself mentions only client_request_id and references poll_after_ms (an output field). It adds a usage note for client_request_id (reuse on retries), which is already in the schema's description, so the marginal value is low. The other parameters (depth, response_mode, etc.) are adequately described in the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action ('Submit an asynchronous, metered design review') and specifies the resource (tenant-authorized HTTPS preview). It also explicitly says 'This tool never edits code,' which distinguishes it from any code-modifying sibling. The verb 'submit' is unique among the sibling tools (get, recheck, cancel, panel_action), so an agent can unambiguously select it.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives concrete usage guidance: 'Reuse client_request_id on retries, then poll design_review_get no faster than poll_after_ms.' This tells the agent how to handle retries and which tool to use for polling. It doesn't explicitly exclude other siblings (e.g., design_recheck, cancel), but for the core submit action the guidance is sufficient. Slightly stronger would be an explicit 'use this to start a review, use design_review_get to retrieve results.'
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
design_review_cancelCancel design reviewADestructiveIdempotent
Request best-effort cancellation of a queued or running review job. Terminal jobs keep their existing state. Cancellation does not edit customer systems and consumes no review units.
| Name | Required | Description | Default |
|---|---|---|---|
| job_id | Yes | ||
| reason | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Typed tool error, returned with isError: true instead of the result envelope. The full code and next_action vocabularies are in schemas/review-error.schema.json. |
| job_id | No | |
| status | No | |
| schema_version | No | |
| upstream_cancellation | No | |
| cancellation_requested_at | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations declaring destructiveness and idempotency, the description discloses best-effort semantics, the terminal-job no-op behavior, and the fact that no customer systems are edited and no review units are consumed. These are material consequences for the agent and are genuinely additive to the structured hints.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, nothing wasted. The core action is front-loaded, and the secondary constraints are compactly chained. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter cancellation tool with an output schema and strong annotations, it captures the essential state constraints, best-effort nature, and safety characteristics. A small mention of confirming the result via design_review_get would have made it fully rounded, but it is not needed to call the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% and the description is silent on both job_id and reason. An agent might infer job_id from the tool name, but the description itself offers no meaning for reason, its optionality, or its use.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Says what it does with a specific verb ('Request best-effort cancellation'), identifies the exact resource (a queued or running review job), and carves out terminal jobs. The backoff semantics and no-edit behavior distinguish it clearly from design_review, design_review_get, and design_review_panel_action.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides clear operational context: applicable to queued/running jobs, best-effort, and no-op for terminal jobs. It does not explicitly name sibling alternatives or say 'check design_review_get to confirm a terminal state,' so it stops just short of full when-to-use routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
design_review_getGet design reviewARead-onlyIdempotent
Get status or a compact, focused, or evidence view for an existing review job. Poll no faster than the returned poll_after_ms. Result reads do not consume review units. Act on review.measurements.violations unconditionally: they are computed from the captured DOM and are true whether or not a model ran. Act on review.findings only when provenance.model_backed is true and coverage.state is full or partial.
| Name | Required | Description | Default |
|---|---|---|---|
| view | No | Result view (default: summary). | summary |
| job_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| job | No | |
| error | No | Typed tool error, returned with isError: true instead of the result envelope. The full code and next_action vocabularies are in schemas/review-error.schema.json. |
| focus | No | |
| budget | No | |
| review | No | |
| recheck | No | |
| evidence | No | |
| findings | No | |
| presentation | No | Emitted by the evidence view only: the honest capability downgrade, naming exactly what the calling host could not render rather than dropping it silently. |
| schema_version | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds substantial behavioral context beyond the annotations. It explains 'Result reads do not consume review units', which is safety-relevant. It also gives actionable guidance on how to interpret two result fields: 'Act on review.measurements.violations unconditionally' and 'Act on review.findings only when provenance.model_backed is true and coverage.state is full or partial'. These nuances are not present in annotations and are crucial for correct use. There is no contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loaded. It states purpose in the first sentence, then provides specific usage (polling) and a second critical behavioral rule (result units) followed by a third interpretation rule. Every sentence earns its place with no fluff or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description is highly complete for a read-only view tool. It tells the agent about the output views, the impact of read operations on review units, the polling mechanism, and the provenance/coverage gate for findings. Given that the output schema exists and annotations already convey idempotence and safety, nothing essential is missing for correct use.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already describes 'view' and its enum/default, covering 50% of parameters. The description enhances meaning by connecting the view options to 'compact, focused, or evidence' and specifying that the job_id refers to an 'existing review job'. While it does not provide detailed semantic descriptions for each enum value, it goes beyond the schema's minimal value descriptions and reinforces the job_id context.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Get'), a clear resource ('design review'), and the exact variants of views available (status, compact, focused, evidence). The phrase 'existing review job' immediately distinguishes it from sibling tools like design_review or design_recheck, which likely create or modify jobs. An agent can reliably identify this as the read/query tool among the sibling set.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description clearly tells the agent when to use it: to get status or views of an existing review job, and it gives a concrete operational guideline ('Poll no fetched than the returned poll_after_ms'). It does not explicitly state when not to use it or mention alternatives (e.g., 'use design_review to start a new review'), but the context of 'existing review job' implies it is not for creating or canceling. The guidance is clear but weak on exclusion.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
design_review_panel_actionAct on a review panel findingBRead-onlyIdempotent
Route an interaction from the interactive review panel: return a grounded finding's fix for the coding agent to apply, or the refs to re-verify. This tool never edits code. An advisory finding returns human_only, never an automatic fix, and a review nothing judged returns unjudged with no fix at all. Reads only; consumes no review units.
| Name | Required | Description | Default |
|---|---|---|---|
| action | Yes | ||
| job_id | Yes | ||
| finding_id | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Typed tool error, returned with isError: true instead of the result envelope. The full code and next_action vocabularies are in schemas/review-error.schema.json. |
| job_id | No | |
| response | No | The panel reducer's routed response: a grounded fix for the coding agent, a human_only referral, an unjudged refusal when nothing judged the review, or the recheck refs. |
| review_id | No | |
| provenance | No | Where the review this action was routed from came from. A routed fix is a string the caller is expected to act on, so the payload says in-band whether anything judged the review that produced it. When model_backed is false, response.type is "unjudged" and no fix is returned. |
| schema_version | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description aligns with the readOnlyHint and destructiveHint annotations by stating it never edits code and reads only. It also discloses specific edge-case behaviors for advisory findings and unjudged reviews, adding detail beyond the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is somewhat repetitive, repeating the read-only idea in multiple phrases ('never edits code', 'Reads only', 'consumes no review units'). It is not excessively long but could be more streamlined.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description explains return outcomes and read-only behavior, but it lacks details about parameter meaning, error cases, or output structure. Given an output schema exists, the description is adequate but not fully complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, and the description only indirectly references 'finding' without clearly defining job_id, action, or finding_id. The action enum values are not explained, leaving parameter semantics largely unspecified.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool routes an interaction from the review panel and returns either a fix or refs to re-verify. It also clarifies the read-only nature, distinguishing it from action-oriented tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives some usage context ('interactive review panel') and mentions outcomes like advisory findings, but it does not explicitly state when to choose this tool over siblings such as design_review_get or design_recheck. No direct alternative guidance is provided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
5 tool updates
v0.1.2- First observed
design_recheck - First observed
design_review - First observed
design_review_cancel - First observed
design_review_get - First observed
design_review_panel_action
TDQS
Scored across 5 tools
Each tool has a clearly distinct purpose: submit review, get status, recheck, cancel, and panel action. There is no overlap between submission and retrieval, and cancellation is separate from panel actions. The descriptions further differentiate them, making misselection unlikely.
All tools share the 'design_' prefix, but the suffix varies: 'review', 'review_get', 'recheck', 'review_cancel', 'review_panel_action'. While 'design_review' is a verb phrase, others combine 'review' with a noun (get, cancel) and 'recheck' is a different verb. The pattern is mostly consistent and readable, but not perfectly uniform.
Five tools is well within the recommended 3-15 range and matches the scope of a review service. Each tool covers a distinct operation in the review lifecycle without redundancy or bloat.
The surface covers the core lifecycle: submit, poll/retrieve, recheck, and cancel, plus an interactive panel action for post-review interactions. Minor gaps like listing all past reviews are not essential for the primary workflow, and the tool set is adequate for its stated purpose.
Maintenance
Related MCP Connectors
MCP server for visual regression testing: triage a PR's UI diffs from your coding agent.
MCP server for secureFlows: token-free URL builders and integration-linting tools for AI agents.
Website QA for your coding agent: audit SEO, performance, security, accessibility over MCP.
MCP server for Mint — AI-powered QA that runs your app in a real browser on every PR.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceMCP server for visual feedback, video direction, and QA assertions on web pages, enabling AI agents to read, reply, and resolve annotations in real time.6MIT
- FlicenseNot gradedqualityAmaintenanceMCP server that exposes web page annotations to AI coding agents, enabling automated implementation of visual feedback and design tweaks.4 npm163-
- FlicenseAqualityDmaintenanceAn MCP server implementing a 7-stage agentic frontend workflow—from design audit to PR review—including AI-driven component generation, browser validation, E2E testing, and CI self-healing.44 npm-

squirrelscanofficial
AlicenseNot gradedqualityAmaintenanceMCP server for website QA auditing, covering SEO, performance, security, accessibility, and agent experience with 260+ rules and AI-optimized output for coding agents.267MIT