dsh-verify
The dsh-verify server enables deterministic, browser-driven acceptance testing of web applications in real headless Chromium. You can:
Run predefined acceptance specs (
verify_spec): Execute JSON spec files or glob patterns against headless Chromium, checking text, classes, computed styles, URLs, screenshots, console/network errors, and more; returns PASS/FAIL verdict with per-step results and a self-contained HTML report.Verify live URLs inline (
verify_url): Run human-style checks (click, fill, expect_text, expect_class, capture_style, expect_style_changed, screenshot, etc.) directly against any live URL without a spec file.Generate and verify checklists (
generate_and_verify): Accept a URL and optional plain-language QA requirements; an AI model drafts an acceptance checklist, then real Chromium immediately executes it. The AI only drafts — the browser is the judge.Check health (
health): Confirm the server and Chromium browser are ready before running verifications.
All verification runs produce self-contained HTML reports with per-step results, pass/fail badges, and screenshots. Tests can also be run with a visible browser for debugging.
dsh-verify
中文 | English
Witness — The browser is the judge. The quality gate for agent-built web apps. Agents say done; the browser proves it. (Witness is the product name;
dsh-verifyis the package name — same thing.)
If Witness catches something for you, ⭐ star the repo — it's how this project stays alive.
You asked an AI to build a web app. It said "done." Does it actually work?
dsh-verify opens a real browser and checks — so you never have to take the agent's word for it.


The quality gate for agent-built web apps. Works with any agent — DeepSeek Harness (dsh), Claude Code, Cursor, Copilot, Codex — and with any CI. You write what a human would check in a browser; a real browser executes it and returns a PASS/FAIL verdict with receipts (screenshots + diff images).
No LLM judges the outcome. The browser is the judge.

Same task. Same AI. Two builds. One missing CSS rule — the agent's self-review passed, a real browser caught it.
Why this exists
We ran a 4-agent web team (spec writer → frontend dev → QA → reviewer). Their own review said:
✅ "All requirements met. No issues found."
In a real browser, the dark-mode toggle did nothing — the .dark class was toggled, but the CSS rule was never written. Every agent self-test passed because there was nothing in the page for the agents to run. No one opened a real browser.
That's the gap: agents verify against what they believe they built, not against what a user actually experiences. Unit tests and static checks can't catch a missing CSS rule.
Build | What the agents said | What a real browser says |
| "No issues found" | ❌ FAIL — background never changes |
| one CSS rule added | ✅ PASS — theme flips |
Same page. Same JS. One missing CSS rule. Two different verdicts.
Related MCP server: Mochi
Why not just ...?
What you might reach for | Its blind spot | What dsh-verify adds |
Hand-rolled Playwright scripts | Every agent project re-writes the same boilerplate; nothing is reviewable as a spec | A JSON spec is the whole contract — write once, reuse across agents and CI |
LLM judges (promptfoo-style evals) | An LLM says "looks right" — it doesn't run the app or see the pixels | A real browser executes clicks, inputs, styles, and returns screenshot receipts |
Agent built-in browser tools | They're the agent's hands — they share the same blind spots as the code they just wrote | dsh-verify is an independent witness, not part of the agent being tested |
Screenshot-only visual tools | They catch pixel drift, not "button does nothing" | Behavior checks: click, expect text/class/style change, console errors, network errors |
The agent graded its own homework. dsh-verify re-grades it in a real browser.
Use it three ways
Entry point | What it's for | One-liner |
MCP server | Your AI agent verifies its own deliverable, mid-session |
|
CLI | You or your CI verify a build/URL |
|
GitHub Action | Every push runs real-browser checks |
|
From any AI agent (MCP)
claude mcp add dsh-verify -- npx -y -p dsh-verify dsh-verify-mcpThen tell your agent, in plain words:
Verify http://localhost:3000 — click
#dark-toggle, then checkbodybackground-color changed. Screenshot it.
Tools exposed: verify_spec (run a spec JSON), verify_url (inline checks, no files), generate_and_verify (the AI drafts the checklist, real Chromium executes it), health.
In CI (GitHub Action)
- uses: 263311487-ux/dsh-verify/.github/actions/dsh-verify@main
with:
spec: demo/fixed.json # spec file or glob
# url: https://staging.example.com # optional override
# out: dsh-verify-out # report output dir (default)The repo dogfoods it: the dogfood workflow asserts the fixed build passes and the buggy build fails on every push.
On the command line
npm install -g dsh-verify # or: npx dsh-verify
npx playwright install chromium # one-time browser download
npx dsh-verify --spec 'specs/*.json'
# [PASS] specs/home.json (5/5)
# [FAIL] specs/cart.json (4/5)
# ❌ expect_text #total: got "0" want "99"What's in the box
Deterministic judge — a real headless Chromium (or Firefox / WebKit) executes human-style checks: click, fill, text, classes, computed styles, URLs, console errors, network errors, pixels.
Receipts, not vibes — every run emits a self-contained HTML report with screenshots and red-highlighted diff images;
--jsonfor machines; exit0/1for CI.Visual regression — screenshot baselines, pixel-diff with thresholds (
expect_screenshot), refresh with--update-baselines.AI-drafted checklists —
dsh-verify gen --url ... --prompt "..."learns the page in a real browser, has an LLM draft the checklist, then executes it deterministically. The AI drafts; it never judges.Multi-browser —
chromium|firefox|webkitper spec or--browser.Zero framework lock-in — a JSON spec is all there is. No config language, no SDK, no vendor.
Example spec
{
"title": "my app",
"serve": "dist",
"browser": "chromium",
"steps": [
{ "action": "goto", "path": "/index.html" },
{ "action": "click", "selector": "#count-btn", "count": 3 },
{ "action": "expect_text", "selector": "#count-btn", "text": "Clicked: 3" },
{ "action": "capture_style", "selector": "#page", "prop": "backgroundColor", "var": "bg_before" },
{ "action": "click", "selector": "#color-btn" },
{ "action": "expect_class", "selector": "#page", "class": "dark", "present": true },
{ "action": "expect_style_changed", "selector": "#page", "prop": "backgroundColor", "var": "bg_before" },
{ "action": "screenshot", "name": "final-state" }
]
}Top-level fields: title, serve (static dir) or base (target URL), browser, steps. Run many at once with a glob; exit is 0 only if all pass.
The report
A self-contained HTML report — every step with a pass/fail badge, selector, and detail, plus screenshots:

Agent Arena — bring your agent
Real-browser benchmark for agent-built web apps: same 3 tasks, same human checks, open entry. Run your model on the board in ~10 minutes:
git clone https://github.com/263311487-ux/dsh-verify && cd dsh-verify
npm install && npx playwright install chromium
export LLM_API_KEY=sk-... # any OpenAI-compatible model
node arena/run.mjs --agent "gpt-5/single" --task all --repeat 1 --submitter yournameYour setup appears on the live leaderboard next to DeepSeek v4-flash / v4-pro: agent-arena. Full rules in docs/ARENA.md.
Prove it (run it yourself)
git clone https://github.com/263311487-ux/dsh-verify && cd dsh-verify
npm install && npx playwright install chromium
npm run demo:fixed # → PASS (11/11)
npm run demo:buggy # → FAIL (exit 1) — the missing .dark rule, caught
npm test # engine self-testsThe repo's own CI runs exactly that — engine self-tests, then asserts fixed passes and buggy fails — so the tool verifies itself on every push.
Agent Arena — can agents ship working web apps?
Same task, same prompt, same human checks — different agents, graded by dsh-verify in a real browser. Latest run (2026-08-19): 44/48 runs passed across 2 models × 2 strategies × 3 tasks, 4 runs per cell. Two counterintuitive findings: the pricier v4-pro single-shot scored below the cheaper v4-flash single-shot (10/12 vs 11/12), and a real-browser self-check loop lifted v4-pro to 12/12 — while v4-flash's self-check crashed once when its own verification report came back as corrupt JSON. Every failure is reproducible and invisible to an LLM judge.
See docs/ARENA.md — methodology, the tasks, and how to run your own agent.
Badge your agent-built app
Built something with an AI agent? Prove it in a real browser and show the world:
[](https://github.com/263311487-ux/dsh-verify)Add a spec, wire the GitHub Action, and the badge is earned, not claimed. See docs/verified-badge.md.
Roadmap
MCP server · AI-drafted checklists · visual regression · multi-browser · GitHub Action · dsh plugin
Agent arena — a public benchmark: give the same task to different agent setups, grade them in real browsers, publish the leaderboard
Spec recorder (browser extension: click through once → spec generated)
Cloud runs + shareable report links + PR comments
Related
dsh-doublecheck — delivery quality gate for DeepSeek Harness (/gate): requirements grill + evidence discipline. Complementary pair: /gate keeps the evidence honest, dsh-verify keeps the browser honest.
falsify — the scientific thinking protocol for AI agents (hypothesis → falsify → evidence → calibrated conclusion). The pair: falsify catches the wrong conclusion, dsh-verify catches the broken output.
Featured in the DeepSeek Harness community — Show Your Plugins: dsh-verify (48-run Agent Arena results in-thread)
License
MIT
Available Tools
4 toolsgenerate_and_verifyA
AI-drafts an acceptance checklist for a URL (LLM writes it, a real browser executes it), then immediately runs it in real Chromium. Pass requirements as a plain-language description of what a human QA should verify (e.g. "dark-mode toggle changes the background color"). Requires DEEPSEEK_API_KEY or OPENAI_API_KEY in the server environment. Returns the drafted spec path plus the PASS/FAIL verdict, per-step results and report path.
| Name | Required | Description | Default |
|---|---|---|---|
| out | No | Output dir for spec + report (default: ./dsh-verify-out) | |
| url | Yes | Target URL to verify | |
| model | No | LLM model (default: deepseek-v4-flash) | |
| headed | No | Run with a visible browser (debug only) | |
| requirements | No | Plain-language QA requirements (optional) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and uses it well: it reveals that an LLM drafts the spec, that it runs in a real browser (implying actual page interaction), and that API keys are required. It also states the output artifacts. It doesn't mention potential side effects on the target URL, but the 'real browser' clause provides transparency.
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?
Four sentences, each with a distinct role: core action, user input guidance, prerequisite, and return values. No redundancy or extraneous details; 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?
Given no output schema, the description adequately bridges the gap by enumerating the return values: spec path, PASS/FAIL verdict, per-step results, and report path. It also covers prerequisites and usage context, making it complete for the tool's moderate complexity.
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 100%, so the baseline is 3. The description goes beyond by providing an example for the 'requirements' parameter ('dark-mode toggle changes the background color') and tying the 'out' parameter to both spec and report paths, which adds meaning not fully spelled out in the schema.
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 opens with 'AI-drafts an acceptance checklist... then immediately runs it in real Chromium', which specifies the verbs (drafts and runs) and resource (acceptance checklist for a URL). This clearly distinguishes it from siblings like verify_spec and verify_url by highlighting the generation step before verification.
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 gives explicit context for use: pass requirements in plain language as QA criteria, and it notes the prerequisite of DEEPSEEK_API_KEY or OPENAI_API_KEY. However, it does not explicitly state when to use this tool instead of verify_spec or verify_url, so it earns a 4 rather than a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
healthA
Check that the dsh-verify MCP server and its Chromium browser are ready to run verifications.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. While it states the purpose, it does not disclose whether the check is read-only, what the result looks like, or what happens if components are not ready. For a health check, this is a notable gap.
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?
A single, front-loaded sentence that is concise and free of filler. It communicates the essential purpose without wasted words.
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 simple 0-parameter tool, the description covers the main purpose but omits the expected response or how to interpret the check result. Since there is no output schema, adding a brief note about the return value would make it more 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?
There are zero parameters, so schema coverage is complete. No parameter documentation is needed, and the baseline of 4 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 tool checks the readiness of the dsh-verify MCP server and its Chromium browser. The verb 'check' and the specific resource distinguish it from sibling tools that actually run verifications.
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 implies this is a pre-flight check before running verifications ('ready to run verifications'), but it does not explicitly state when to use this tool versus the verification siblings, nor does it provide exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
verify_specA
Run a dsh-verify acceptance spec (JSON file, or glob) against a real headless Chromium. The spec may serve a local static dir (spec.serve) or target any URL (spec.base / step.url). Returns PASS/FAIL with per-step results and a self-contained HTML report path. Exit-code semantics: ok=true means every step passed. This is deterministic — no LLM judges the outcome.
| Name | Required | Description | Default |
|---|---|---|---|
| out | No | Output dir for report.html + screenshots (default: ./dsh-verify-out) | |
| url | No | Optional target URL override (spec.base / step path ignored) | |
| headed | No | Run with a visible browser (debug only) | |
| specPath | Yes | Path to the spec JSON file or glob (e.g. specs/*.json) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the burden of behavioral disclosure. It explains that the tool is deterministic ('no LLM judges the outcome'), returns PASS/FAIL with per-step results and an HTML report, and defines exit-code semantics. It does not mention side effects like output directory creation or browser dependency, but these are partially inferable from the schema and tool nature.
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 four concise sentences with no fluff or repetition. It front-loads the core action and packs essential nuance about targets, outputs, and determinism into a compact space.
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 tool has no output schema, but the description explicitly covers return values (PASS/FAIL with per-step results and HTML report) and exit-code semantics. All four parameters are documented in the schema, and the description adds behavior context. There are no significant gaps for an agent to invoke 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 100%, so the parameters are well-documented in the schema. The description adds modest context by explaining spec structure (spec.serve, spec.base/step.url) and that specPath can be a glob, but it does not materially enhance parameter semantics beyond what the schema already provides.
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's purpose: 'Run a dsh-verify acceptance spec (JSON file, or glob) against a real headless Chromium.' This is a specific verb+resource pairing. It also distinguishes itself from siblings like verify_url by focusing on acceptance specs rather than single URLs, and from generate_and_verify by not mentioning any generation step.
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 useful context on when to use the tool, such as the ability to serve a local static dir or target any URL, implying it is for spec-driven verification. However, it does not explicitly state when to use an alternative like verify_url for simple URL checks, so it lacks direct when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
verify_urlA
Verify a live URL against a list of human-style checks, driven by a real headless Chromium. Checks are dsh-verify steps: goto/click/fill/wait/expect_text/expect_class/capture_style/expect_style_changed/expect_url_contains/expect_navigation/expect_console_errors/expect_network_errors/screenshot. If no goto step is given, a goto to the url is prepended. Returns PASS/FAIL with per-step results and a self-contained HTML report path. Deterministic — no LLM judges the outcome.
| Name | Required | Description | Default |
|---|---|---|---|
| out | No | Output dir for report.html + screenshots (default: ./dsh-verify-out) | |
| url | Yes | Target URL to open | |
| checks | Yes | Human-style checks, e.g. [{action:"click",selector:"#dark-toggle"}, {action:"capture_style",selector:"body",prop:"backgroundColor",var:"bg"}, {action:"expect_style_changed",selector:"body",prop:"backgroundColor",var:"bg"}] | |
| headed | No | Run with a visible browser (debug only) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description fully discloses key behaviors: it uses a real headless Chromium, lists all supported check steps, automatically prepends goto if missing, returns PASS/FAIL with per-step results and an HTML report, and emphasizes deterministic execution (no LLM judging). This goes far beyond a simple 'verify' statement.
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 three sentences long and extremely information-dense. It front-loads the core purpose and packs the check action list and output semantics into a compact, readable format with no irrelevant details.
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?
Despite having no output schema, the description clearly explains what the tool returns (PASS/FAIL, per-step results, HTML report path) and how it operates. It could mention potential side effects of click/fill actions or network dependencies, but the given detail is strong for a verification tool.
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 input schema describes all four parameters with 100% coverage, so the baseline is 3. The description adds operational context for the checks parameter (list of actions, prepending goto) and clarifies output behavior, but does not significantly augment the schema beyond that.
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 uses a specific verb ('Verify') and resource ('a live URL') and elaborates on the method with a detailed list of check actions. It clearly distinguishes itself from siblings (health, verify_spec, generate_and_verify) by focusing on human-style browser-based verification of a live URL.
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 implies when to use this tool: when you need to run human-style browser checks against a live URL. It does not explicitly mention alternatives or exclusions, but the context is unambiguous and sufficient for tool selection.
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. Dates show when Glama detected each change.
4 tool updates
v0.1.0- First observed
generate_and_verify - First observed
health - First observed
verify_spec - First observed
verify_url
TDQS
The tools are mostly distinct: health checks readiness, verify_spec runs a spec file/glob, verify_url runs ad-hoc checks on a URL, and generate_and_verify combines AI drafting with execution. There is slight overlap between verify_spec and verify_url, but input types clearly differentiate them.
Naming is mostly snake_case but inconsistent in style: health is a noun, verify_spec and verify_url follow verb_noun, while generate_and_verify is a compound verb phrase. The pattern is still readable but not uniform.
With 4 tools, the server is well-scoped. Each tool serves a distinct purpose in the verification workflow: readiness check, spec execution, live URL verification, and AI-assisted generation, with no redundancy.
The domain of running headless Chromium verifications is well covered: health, spec-based execution, ad-hoc checks, and AI-drafted specs. Minor gaps include no standalone spec generation without execution and no spec management, but these are not critical for the core workflow.
Maintenance
Related MCP Connectors
Browser-based QA for AI-built software. Test pages with real browsers via agents.
MCP server for Mint — AI-powered QA that runs your app in a real browser on every PR.
- mcpOAuthcom.screenshotink
Screenshot, diff, audit and sitemap-capture any web page — 5 MCP tools for AI agents.
Hosted browser for AI agents: screenshots, post-JS DOM, console, WCAG. No install, no API key.
61
Related MCP Servers
- AlicenseNot gradedqualityFmaintenanceCode-aware browser testing agent — reads your codebase, understands functionality, tests every element, reports with screenshots. Works as MCP server for Cursor/Claude Code or standalone CLI.1735MIT
- AlicenseBqualityCmaintenanceBrowser automation MCP server with persistent memory for AI assistants, enabling automated web testing and workflow replay with self-healing selectors.543MIT
- AlicenseCqualityAmaintenanceAn MCP server that enables AI agents to autonomously test, debug, and analyze web interfaces visually using Playwright, with 30 tools for screenshots, workflows, performance, and visual comparison.304081ISC
- FlicenseNot gradedqualityBmaintenanceMCP server that enables AI agents to automate browser testing via Chromium, providing tools for navigation, interaction, and inspection.-
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/263311487-ux/dsh-verify'
If you have feedback or need assistance with the MCP directory API, please join our Discord server