mcp-evidence
This server drives a real Chromium browser to verify and document that features work, producing screenshots, video, and trace files as evidence.
Start a session (
start_evidence_session): Launch a Chromium browser context with video and trace recording enabled for a named feature, optionally scoped to a base URL. Returns asessionIdfor subsequent calls.Navigate (
navigate): Direct the browser to any URL (absolute or relative to the session's base URL).Click (
click): Interact with page elements using CSS/text selectors or ARIA role and name attributes.Fill (
fill): Type values into form inputs located by CSS selector.Wait for (
wait_for): Pause execution until an element reaches a desired state (visible,hidden,attached, ordetached).Screenshot (
screenshot): Capture and save PNG screenshots immediately into the evidence directory, with a custom label used in the filename.Finish session (
finish_evidence_session): Close the browser, finalize video and trace, write amanifest.json, and receive a report of any console errors, uncaught exceptions, or failed network requests detected during the session.Passive error monitoring: Every session automatically records browser console errors, uncaught page exceptions, and failed/non-2xx network requests into
manifest.json, ensuring silent failures aren't missed.Auto-cleanup: Sessions idle for 10 minutes are automatically finalized, and open sessions are flushed on process termination to prevent lost evidence.
Click on "Install 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-evidenceCapture evidence for checkout flow on localhost:3000"
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.
mcp-evidence
An MCP server that drives a real Chromium browser (via Playwright) and packages the run into evidence — screenshots, a video, and a Playwright trace — proving a feature works. Meant for an agent to call after implementing something, as a verification step.
Generic and reusable: no assumptions about any particular app's routes or
auth. You pass a baseUrl per session, and evidence is written into the
consuming project's working directory at
.evidence/<featureName>/<timestamp>/.
Install
Browsers aren't bundled — install Chromium once per machine:
npx playwright install chromiumRegister with Claude Code
Per-user (available in every project):
claude mcp add --scope user evidence -- npx -y github:meovan07/mcp-evidenceOr per-project, add to .mcp.json:
{
"mcpServers": {
"evidence": {
"command": "npx",
"args": ["-y", "github:meovan07/mcp-evidence"]
}
}
}This repo is public, so no GitHub credentials are needed on the machine
running npx.
Consuming projects should add .evidence/ to their own .gitignore.
Related MCP server: Playwright MCP
Tools
Tool | Purpose |
| Launches a browser context with video + trace recording on. Returns |
| Goes to |
| Clicks an element, located by CSS/text |
| Fills a form field. |
| Drags a source element onto a target, firing native HTML5 drag events. |
| Drags an element by a pixel distance — no drop target. For resize handles, sliders, swipe gestures. |
| Waits for an element to reach a state (default |
| Simulates losing ( |
| Mid-session version of |
| Runs a JS expression in the page, returns the (JSON-serializable) result. |
| Returns the accessibility tree as YAML (role, name, ref, bounding box) — see below. |
| Saves a PNG immediately into the evidence dir. Survives even if the session later errors. Pass |
| Closes the context, finalizes |
A session left open for 10 minutes with no tool calls is auto-finished. The
server also flushes any open sessions on SIGINT/SIGTERM so evidence isn't
lost if the process is killed mid-run.
Diagnostics on failure
click, fill, drag, drag_by_offset, and wait_for are the tools most
likely to fail while you're still figuring out an unfamiliar page — wrong
selector, element not visible yet, wrong assumption about the DOM. Rather
than returning a bare Playwright timeout, the error has a compact
accessibility snapshot of the page auto-attached, so you can usually see
what actually happened and correct course in the same round-trip instead of
needing a follow-up snapshot()/evaluate() call just to find out why.
Playwright's own error text is also cleaned up before it reaches you: terminal ANSI color codes are stripped (pure noise outside a terminal), and the actionability retry log — which can run to dozens of near-identical "waiting for element to be visible, enabled and stable" lines on a slow or animating element — is capped at the first few lines plus a count of how many were omitted.
Browser choice
start_evidence_session defaults to Chromium. Pass browser: "firefox" or
browser: "webkit" to use a different engine — webkit is the open-source
engine behind Safari, the closest available option for catching
Safari-specific bugs (though not a literal Safari build; some macOS-only
behavior like Intelligent Tracking Prevention may differ slightly). Install
the extra engines once per machine:
npx playwright install webkit firefoxmanifest.json records which engine a session used (browserEngine).
Every session also passively records, into manifest.json, anything a
screenshot or video wouldn't show: browser console errors and uncaught page
exceptions. finish_evidence_session reports the counts directly so a
silent failure doesn't slip through unnoticed.
Every request the page makes — not just failures — is also logged to
network.json (method, url, resource type, status, timing), the same data
Chrome DevTools' Network tab shows. manifest.json keeps a filtered
networkIssues list (non-2xx/failed only) plus a networkRequestCount for a
quick read without opening the full log. (The trace.zip already had this
same data in Playwright's own trace viewer; this just makes it directly
readable by the calling agent too, not only a human opening the trace UI.)
Reusing an authenticated session (storageStatePath)
Every session starts from a completely clean browser context by default —
good for testing a fresh visit, but it means any auth-gated flow (email OTP,
password login) has to be redone from scratch on every single run. Pass
storageStatePath to skip that:
start_evidence_session({ featureName: "checkout", baseUrl, storageStatePath: ".evidence/.auth/test-user.json" })First run: the file doesn't exist yet, so the session starts fresh (logged out) as usual. Log in normally with
navigate/fill/click(usingwait_for_emailfrommcp-evidence-apiif it's an OTP flow). Whenfinish_evidence_sessionruns, the session's cookies + localStorage are saved to that path.Every subsequent run that passes the same
storageStatePath: the file exists, so the session loads it and starts already signed in —start_evidence_session's response says[loaded existing storage state, likely pre-authenticated]. The state is refreshed on everyfinish_evidence_sessiontoo, so rotating session tokens stay current.
This file contains live session credentials — treat it exactly like a
password. Store it under .evidence/ (already covered by the gitignore
guidance below) or another path you've confirmed is gitignored, never commit
it, and use a separate path per test account/user if you're testing more
than one identity.
Mobile / tablet emulation (device)
Pass a Playwright device name to emulate a real device's viewport, user agent, touch support, and pixel ratio instead of a generic desktop window:
start_evidence_session({ featureName: "checkout mobile", baseUrl, device: "iPhone 13" })Common values: "iPhone 13", "Pixel 5", "iPad Pro 11" — see
Playwright's device list
for the full set (includes landscape variants, older devices, etc.). An
invalid name throws immediately with that link. manifest.json records
which device a session used.
PWA testing
Two genuinely different things fall under "PWA testing," with different support levels here:
Offline / service-worker-cache behavior — fully supported today via
set_network({ sessionId, offline: true }). This is the actual mechanism a PWA is tested against: does it serve cached content, show a fallback UI, sync back up when reconnected."Installed" look/behavior (
display-mode: standalone) — partially supported, and it's worth understanding the real limitation rather than assuming it's fully covered. There is no browser API — CDP or otherwise — that can force the native CSS@media (display-mode: standalone)feature to match (confirmed by testing every parameter combination of Chrome DevTools Protocol's media-emulation command, and cross-checked against Puppeteer's docs, which list onlyprefers-color-scheme,prefers-reduced-motion, andcolor-gamutas supported — notdisplay-mode). WhatdisplayMode/set_display_modeactually do is override the JSwindow.matchMedia()function, so an app's JS install-detection logic (matchMedia('(display-mode: standalone)').matches— a common real pattern, e.g. to hide an "Install app" banner once running standalone) reports the requested mode correctly. Any CSS written as@media (display-mode: standalone) { ... }will not be affected — the browser's CSS engine evaluates that independently of the JS function, and nothing in Playwright or CDP can override it.
start_evidence_session({ featureName: "pwa install banner", baseUrl, displayMode: "standalone" })
// or mid-session:
set_display_mode({ sessionId, mode: "standalone" })For a full pixel-accurate "how does this look actually installed" check —
CSS included — there's no automatable substitute for genuinely installing
it (desktop: Chrome's --app=<url> launch mode; mobile: an actual
home-screen install on a real or emulated device), which is outside this
tool's scope.
Accessibility snapshot (snapshot)
Reach for this before reaching for evaluate or trial-and-error click
calls to figure out what's on a page. It returns Playwright's aria snapshot
— a YAML tree of role, accessible name, a stable ref, and (by default) a
bounding box for every element:
snapshot({ sessionId })
-> - generic [ref=e1] [box=0,0,393,727]:
- button "Ask Coach..." [ref=e45] [box=40,412,321,24]
- button [disabled] [box=337,775,40,40]:
- img [box=347,785,20,20]Two things this surfaces for free that a screenshot or DOM query won't:
elements with missing accessible names (the second button above is
icon-only with no aria-label — a real accessibility gap, not just
inconvenient for automation), and disabled state (explains why a filled
form's submit button won't respond, immediately, instead of via minutes of
click-timeout debugging). Pass selector to scope it to part of the page
instead of the whole thing, or boxes: false to drop the bounding boxes
if you only need structure.
Distance-based drag (drag_by_offset)
drag() is element-to-element (drag this onto that) — built for
reordering/drop-target interactions. Some gestures have no target element:
a bottom-sheet resize handle, a slider, swipe-to-reveal. drag_by_offset
grabs selector and moves the mouse by (dx, dy) pixels instead:
drag_by_offset({ sessionId, selector: "#resize-handle", dx: 0, dy: -250 })It uses Playwright's real mouse API, dispatched via CDP as trusted OS-level
input — not JS-synthesized PointerEvents. That distinction matters: some
UI libraries (Radix, among others) ignore untrusted synthetic events
entirely, so a dispatchEvent(new PointerEvent(...)) approach can silently
no-op even though the element clearly has a pointerdown listener attached.
Validated against both a native <input type="range"> (jumped straight to
its max when dragged past the track) and a custom pointerdown/
pointermove-based drag handle (moved exactly the requested distance) —
the same pattern that didn't respond to synthetic events in earlier testing.
Example
start_evidence_session({ featureName: "checkout flow", baseUrl: "http://localhost:3000" })
-> sessionId, evidenceDir
navigate({ sessionId, url: "/cart" })
click({ sessionId, role: "button", name: "Checkout" })
fill({ sessionId, selector: "#email", value: "test@example.com" })
wait_for({ sessionId, selector: "#confirmation", state: "visible" })
screenshot({ sessionId, name: "confirmation" })
finish_evidence_session({ sessionId, summary: "Checkout completes and shows confirmation" })Resulting evidence directory:
.evidence/checkout-flow/2026-07-08T07-52-21-042Z/
0-confirmation.png
video.webm
trace.zip
network.json
manifest.jsonView the trace with npx playwright show-trace trace.zip.
Known limitations
If the process is killed within roughly a second of a session starting or navigating (tracing/video still warming up), the video or trace for that session may be incomplete or missing. Screenshots and
manifest.jsonare written eagerly and always survive. This doesn't affect the normal flow of callingfinish_evidence_sessionat the end of a run.One Chromium process per session. Idle sessions are reaped after 10 minutes to avoid orphaned processes.
Development
npm install
npm run build # tsc -> dist/
npm run dev # tsc --watch
npm start # node dist/index.jsMaintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseBqualityDmaintenanceEnables web browser automation through Playwright, providing tools for navigation, element interaction, screenshot capture, and accessibility snapshots. Uses streamableHttp transport for seamless integration with MCP clients.Last updated61,144MIT
- FlicenseBqualityDmaintenanceEnables AI assistants to interact with web browsers in real-time through Playwright, providing DOM access, screenshots, and interaction recording to generate accurate, context-aware test scripts.Last updated511,13932
- Flicense-qualityDmaintenanceEnables automated browser testing of web applications using Playwright, supporting user interactions, form submissions, console monitoring, network request inspection, and visual verification through screenshots.Last updated
- Alicense-qualityCmaintenanceEnables browser automation and web interaction control through Playwright, allowing Claude Code to navigate, click, fill forms, take screenshots, and manage sessions.Last updated686MIT
Related MCP Connectors
Hosted real Google Chrome MCP with per-user persistent state. Navigate, click, type, screenshot.
Automate cloud browsers to navigate websites, interact with elements, and extract structured data.…
Browser MCP for logged-in tasks. Uses your Chrome — credentials stay local. Zero-token replay.
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/meovan07/mcp-evidence'
If you have feedback or need assistance with the MCP directory API, please join our Discord server