Skip to main content
Glama

SceneScout

Your coding agent, turned into an exploratory QA tester for any web app.

Works with Claude Code · Cursor · VS Code (Copilot) · Codex CLI · Gemini CLI · Copilot CLI · Windsurf · any MCP client

test npm license: MIT node >= 22.19

🌐 Website · 📖 Guide · 🐛 What it catches · 🎬 QA with evidence · 🚀 Get started · 🚦 CI · 🔒 Safety · 📚 Docs

Scripted end-to-end tests answer one question: does this exact flow still work? They say nothing about the rest of the app. SceneScout lets the agent you already use explore a running web app like a curious, thorough tester. It clicks, fills forms, switches roles and calls the API behind a hidden button, then writes a report of what is broken and what could be better, with a picture and evidence for every line.

Try it on any app you are allowed to test. No account, no API key, no setup:

npx -y scenescout http://localhost:3000
flowchart LR
  A["🧠 Your coding agent<br/>Claude Code, Cursor, Copilot…"] -- MCP --> S["🔭 SceneScout<br/>browser · checks · memory"]
  S --> App["🌐 Your running app"]
  S --> R["📋 Report<br/>plain words + pictures"]
  S --> E["🎬 Evidence<br/>replay, videos, test report"]

👥 Who it's for

🛠️ Developers

🧑‍💼 QA, product and non-technical teams

Findings with the request that failed (GET /api/orders?status=archived → 500), the steps, and a Playwright regression-test skeleton

Each problem in plain words first: what was done, what was expected, what happened, and a picture of the page

Next to the source, the file behind the bug and a likely fix

Visible problems shown, not described: a covered button, a broken image, text too faint to read

A deterministic gate for pull requests, with SARIF for code scanning

Journeys recorded step by step, as frames and video, so a pass is something you can watch

Runs from your editor's agent, or unattended in CI

A test report laid out by your template, with expected and actual results, deviations and blank sign-off rows

Related MCP server: visual-ui-debug-agent-mcp

🐛 What it catches

A real run against the small demo app in this repository, which has bugs planted on purpose. The two you can see are outlined:

It filed twelve findings. A few from the report:

🔴 [HIGH] A double-click on Create order creates two orders 2× click fired the same state-changing request 2× (POST /api/orders)

🔴 [HIGH] A clerk can approve an order by calling the endpoint the page hides from them POST /api/orders/1037/approve 200 as clerk: the button was hidden, the server did not agree.

🔴 [HIGH] Filtering orders by Archived fails, and the page shows an empty table instead of an error GET /api/orders?status=archived → HTTP 500

🟠 [MEDIUM] The "New: bulk import" badge sits on top of the All orders button (callout 1) "All orders" overlaps "New: bulk import" (81%), measured from layout boxes, no screenshot needed.

What it looks for, on every page, after every action:

  • 📐 Broken layout, from geometry: controls that overlap, sit off-screen, hide under a sticky bar or can never be scrolled into view. The CSS bugs a person spots at a glance, found without one.

  • 🧨 Real breakage: console errors, crashes, failed requests, 4xx and 5xx responses, broken images, dead-end pages.

  • 🔓 Permission leaks: it calls the app's own API as each role, so "the button is hidden" becomes "the server refuses it", or doesn't.

  • 🤥 Pages that lie: "Saved!" after the server refused the save, or an empty table after the request failed.

  • 👆 Impatient users: a double-click that sends the same order twice.

  • ♿ Accessibility and craft: contrast, focus, labels, target sizes, spacing and type, with a 0 to 100 score per page.

  • 🧭 Friction: how many steps a task takes, and where a user had to go back.

  • 💉 Security smells: typed markup that comes back as an element, and tokens posted to any window.

Everything it checks.

🎬 Automated QA with evidence

Save the journeys that matter, the happy paths and the ones that must fail politely, and scenescout check replays them on every pull request with no model involved. Recorded, each run leaves proof you can watch and hand to someone who never opens a terminal.

flowchart LR
  PR["🔀 Pull request"] --> C["🚦 scenescout check<br/>--record --video --template"]
  F["📝 Saved journeys<br/>.scenescout/flows/*.json"] --> C
  C --> G["✅ / ❌ A gate on the pull request"]
  C --> RP["🖼️ replay.html<br/>every step, with frames"]
  C --> V["🎞️ A video per journey"]
  C --> TR["📄 Test report<br/>your template, SHA-256 manifest,<br/>blank sign-off rows"]

A journey is a few lines of JSON, written by hand or kept from a flow your agent just walked. This is the demo's happy path:

{
  "name": "place an order",
  "id": "TC-01",
  "requirements": ["REQ-ORD-1", "REQ-ORD-2"],
  "steps": [
    { "action": "navigate", "target": "/orders-new.html", "expected": "The new-order form is shown" },
    { "action": "type", "target": "testid=new-order-customer", "value": "Harbour Bakery", "expected": "The customer is filled in" },
    { "action": "type", "target": "testid=new-order-items", "value": "4", "replace": true, "expected": "The item count is 4" },
    { "action": "click", "target": "testid=new-order-submit", "expected": "The order is created" },
    { "action": "expect-request", "request": "POST /api/orders", "status": "2xx" },
    { "action": "expect-element", "target": "testid=new-order-created-link", "state": "visible", "expected": "A link to the new order is shown" }
  ]
}

Against the demo app, with the three journeys in examples/flows (one creates an order, so the check is allowed to send it):

npx scenescout check http://127.0.0.1:4173 --flows examples/flows --mode read-only --flow-writes allow \
  --record --video --template examples/report-template.json

The journey, as it ran (one of the videos it filmed):

The replay page: each journey with a pass or fail badge. A journey that broke opens at the step that broke, with the page as it was after every step:

The test report, laid out by a template you write once: test IDs, the requirements each covers, expected and actual results, a screenshot per step, every deviation listed again for the reviewer, and the SHA-256 of each piece of evidence. SceneScout signs nothing; the sign-off rows are for your people.

Everything is one self-contained HTML page per report, with no scripts, nothing loaded from the network, and a layout that prints. Recording a check and a test report from a template have the details, including what to keep out of the pictures.

📺 Watch it work

A narrated eight-minute tour of every feature, on the demo app, is on the website.

Each exploratory run opens a live view on your machine, with one card per agent: what it is doing, the page it is on, and a feed of every action. Three agents are testing the demo app in parallel here:

You can read the report while the agents are still working, and scrub back through any session's timeline. Beside report.md, every run writes report.html, the whole run as one self-contained page; ask for a recorded run and it also keeps a frame after every action.

✨ Why it's different

  • 🧠 Your agent is the brain, so no extra API key. The engine contains no model. It gives the agent you already pay for deterministic tools and the testing method to use them.

  • 📐 It reads structure, not pixels. The agent sees every element with its role, state and layout box, so overlap and broken images are measured, not guessed from a screenshot.

  • 🛡️ Safety is enforced on the network, not requested in a prompt. Every request the page sends is judged against the session's write mode, and a request the mode refuses never reaches your server.

  • ✅ "Done" is a contract. The report lists everything not tested, and at the extensive level refuses to finish while any known page is unvisited.

  • 🧠 It remembers. Each run starts from what the last one learned, and re-tests the bugs earlier runs left open.

  • 📊 It is measured, not asserted. Every change to how it explores is scored against an app with planted bugs and a held-out app it is never tuned on (the log):

xychart-beta
  title "Planted defects found per run, demo app (13 planted)"
  x-axis "Run" ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12"]
  y-axis "Found" 0 --> 13
  bar [11, 12, 9, 10, 11, 11, 10, 10, 11, 13, 11, 11, 12]

Each bar is one run of eight parallel agents, re-scored against today's answer key. One run is noisy: read the trend across runs, not a single bar.

🚀 Get started

1. Install for your agent (Node 22.19 or newer):

npx -y scenescout install                      # Claude Code: skill, MCP server and the test browser
npx -y scenescout install --client cursor      # or vscode, codex, gemini, copilot, windsurf
npx -y scenescout doctor                       # every line should be a ✓
  • Claude Code plugin: /plugin marketplace add brunoboto96/SceneScout, then /plugin install scenescout@scenescout-marketplace. The command becomes /scenescout:scenescout.

  • Claude Desktop: download scenescout-X.Y.Z.mcpb from the latest release and open it. No terminal needed. In the chat, pick Check my site from its prompts to start a guided check without writing a prompt (guided prompts).

  • Any other MCP client: add a stdio server whose command is npx -y scenescout@3.35.0 serve. Each client's config.

2. Start your app, then a fresh session of your agent, and ask:

Use SceneScout to test http://localhost:3000

In Claude Code there is a command too: /scenescout --url http://localhost:3000 --level medium. On its own, /scenescout asks instead: where your client can show a form, one guided form (the address, what to check, how you sign in, how careful to be and how thorough), and otherwise four plain questions in chat. A care level that writes on a site that is not on your computer, or that creates test data, asks you to confirm it in a second form the agent cannot answer (care levels). While it runs, scout_status follows the check in plain words, says what went wrong in one sentence with one thing to do (the site does not open, the sign-in ran out, the check ran out of time), and at the end the problems come back as cards you can mark "not a bug". After a fix, Re-check after a fix checks them again in the care level they were found in, never a looser one, and a check you want to repeat can be saved by name (never with a password or token) and run again. Is it safe to run on my live site? Rather press buttons than write prompts? The optional mod's /scenescout-guided panel does the same from a form in the Claude Code CLI or the desktop Code tab (the mod).

3. Read the report in .scenescout/report.md. It opens with a Summary in plain words (what was checked, what was found, the problems as a table, and each problem's steps, what was expected and what happened), then the Evidence (each problem's picture, on a run that has them), with the Technical details and, in report.html, the Steps folded one click away. A complete example. To hand it round, ask for a team report (scout_team_report, or Make a team report in the chat's menu or the guided panel): .scenescout/team-report.html has a cover, each problem as a card with its picture, what was not checked and blank sign-off lines, with an evidence folder beside it holding the pictures and a manifest of every file's SHA-256. To file problems as GitHub or Jira tickets, pick File problems as tickets (or File as tickets on the guided panel): you see a preview first, and SceneScout files only after you say yes in its own form (how).

No app handy? Clone this repository and run npm run demo:serve: the demo app starts on http://127.0.0.1:4173, and its README lists every planted bug.

Behind a sign-in? Sign in once yourself, SSO and MFA included, and every session reuses it:

npx -y scenescout login http://localhost:3000 --role admin    # then: /scenescout --role admin

Signing in covers roles, expiry and scripted sign-in for CI.

🚦 In CI

What it does

Needs a model?

scenescout check

A deterministic gate: measures every page, replays your saved journeys and visual baselines, fails only on what it can prove; recorded, it leaves the evidence above

No

scenescout ci

An unattended exploratory run, driven by the Anthropic or OpenAI API. It reports and never fails the build

An API key

/scenescout qa

A comment on a pull request that tests its preview deploy and replies with the results; /scenescout qa check runs your own check instead

An API key (qa check: none)

scenescout export

Files the findings as GitHub or Jira issues, each once

No

scenescout preflight

Checks in seconds, with no browser, that the runner can reach the app, that a saved sign-in has not expired and, when asked, the model's API; each cause has its own exit code

No

A gate on every pull request that keeps its evidence, as a GitHub Action:

- uses: brunoboto96/SceneScout@v3
  with:
    url: http://127.0.0.1:3000
    record: on
    video: on
    template: tests/report-template.json

docs/ci.md has complete workflows, every option, and the same check on GitLab CI, CircleCI or any shell.

Ask for it on a pull request

Type a command in a pull request comment and SceneScout answers in the thread, with pictures taken by a real browser:

Comment

Reply

/scenescout qa

Explores the pull request's preview and replies with what it found

/scenescout qa show the Save button

A picture of that element

/scenescout qa compare the Save button

The element on the base and on the pull request, with the changed pixels highlighted

/scenescout qa check

Runs your saved journeys on the branch and replies with each one's result; the video of every journey is in the run's files

The preview commands test a deployed preview, so the pull request's code never runs beside the model's key; qa check runs your own workflow and uses no key. Setting it up.

🔒 Safe by default

Mode

What may leave the page

🔵 observe

GET, HEAD and OPTIONS requests, signing in, signing out and refreshing a token, and any POST you name as a read that does not look destructive. Any other form that posts is refused. The default for a first look and for an agent's run on a remote site with no source

🟢 read-only

Also ordinary form posts, which can create a record or change one that was there. PUT, PATCH, DELETE, requests that look destructive and clicks on controls labelled delete, archive and the like are refused. The default for scenescout check and for an agent's run on a local app

🟡 safe-write

Also PUT, PATCH and DELETE, but only on records this run created

🔴 destructive

Everything. Only when you say the data is disposable: the agent is told never to choose it, and the config file below can rule it out

A team can commit .scenescout/config.json to cap what any agent may choose, for example {"preset": "strict"} to keep every run in observe and the browser on the app's own host (the config file).

SceneScout sends no telemetry. Every path by which data leaves the machine (the agent's model, scenescout ci, export, /scenescout qa, CI artifacts, downloads), what each carries and how to turn it off is in What leaves the machine. {"egress": "none"} in the config file makes SceneScout refuse every one it sends itself; it cannot stop your coding agent from sending what it reads to its own model. {"redactPageText": "pii"} masks email addresses, phone numbers and card numbers in what the tools return to the agent, at the cost of hiding bugs that are about that content.

What the policy cannot stop: a link is opened like any page, so a link that changes something just by being opened (an unsubscribe link) is followed, unless you turn on refusing those in observe and read-only; only HTTP is judged, so messages over a WebSocket are not; and in Firefox and WebKit the later hops of a redirect that keeps a write's method go out unjudged. Which refusals are guarantees and which are pattern matching is in the Safety model, and scenescout policy explain POST <url> says how any one request would be judged in each mode.

The policy sits on the network, so a blocked request never reaches your server. The page gets a refusal instead, which is how SceneScout catches a page that claims success anyway. A saved journey that creates something, like the order above, runs only when the check is told --flow-writes allow, against a test environment. Findings, memory and reports stay in a .scenescout/ folder that keeps itself out of git.

IMPORTANT

Only test sites you own or are allowed to test.Safety model.

📚 Documentation

Start here

A first look, install, a first run, reading the report, the live view

Ways to use it

Interactive runs, parallel agents, CI, pull-request QA, filing issues

What it checks

Every check and every scout_* tool

Signing in · Safety model

Roles and saved logins; what each mode refuses and why

What leaves the machine

Every path data leaves by, to whom, and the egress setting

Network requirements

Every host each command needs, scenescout preflight to check a runner reaches them, how a failure on the network is told from the app's (with an optional retry), running behind a proxy or a firewall's allowlist header, caches, mirrors and self-hosted runners

Recipes

Setups for seven kinds of project

Configuration reference

Every option, environment variable and action input

Troubleshooting

Symptoms and fixes, upgrading and uninstalling

Running it in CI

Saved journeys, recording, test reports from templates, every workflow

How it works

Diagrams of a run, an action, the write policy, lanes

Benchmark · Validation

How runs are scored against answer keys, and runs on public apps

Design decisions

Why the rules are what they are

🔧 Contributing

Start with VISION.md (what is in scope) and CONTRIBUTING.md (local setup and how changes land). AGENTS.md holds the house rules for people and coding agents alike.

Found a way past the write policy, or another security problem? Report it privately: SECURITY.md.

MIT licensed.

Available Tools

48 tools
scout_attachA

Launch a browser and attach to a running web app. First attach in this conversation and you have read neither the SceneScout skill nor scout_playbook? Call scout_playbook before this. Write policy is enforced at the NETWORK layer: mode='observe' lets out only GET, HEAD and OPTIONS, plus signing in, signing out and token refresh, and POSTs the user named in readPosts; every other request is blocked — choose it for a target that holds real data, where even an ordinary form submission would create a record; mode='read-only' (default) blocks destructive-labeled elements AND all PUT/PATCH/DELETE + destructive POSTs, but lets ordinary form POSTs through; mode='safe-write' allows creating data and permits updates/deletes ONLY on resources this session created (use when the user wants create/edit flows tested); mode='destructive' allows everything — ONLY when the user explicitly confirmed a disposable/seeded environment. Pass role to sign in with a login the user saved by scenescout login <url> --role <name>, or a Playwright storage-state JSON as storageStatePath. Pass session to keep MULTIPLE roles alive at once (one browser each, genuinely concurrent) for collaboration testing — target each directly with every tool's session param, or use scout_session to set which one is the default; coverage and findings merge into one project memory.

Inputs: url (required), mode, open, role, +18 more.

scout_backB

Go back in browser history (tests back-button resilience).

Inputs: task, leave, session, objective.

scout_captureA

Save a PNG of ONE element — its bounds plus a margin, from a real screenshot — under .scenescout/captures/, to show a person how it looks. Give the element's ref from the latest scout_snapshot. Not a way to judge design: scout_design_audit measures it.

Inputs: key, ref, name, margin, +1 more.

scout_cardsFinding cardsA
Read-onlyIdempotent

Show the project's findings as plain cards, worst first: impact (Blocks users, Annoying, Cosmetic, Worth a look), title, what kind of problem, the page, numbered steps, what was expected, what happened, and the finding id. Use it at the end of a guided check, or whenever the person wants to read what was found in plain words; post each card's text as it is. By default fixed findings and the ones the person marked not a bug are left out (the count of the second is given; filter {feedback: ["not-a-bug"]} lists them). Pass ids to show exactly those. pictures: "inline" puts each card's picture in the result as an image (at most 10, at most 1024 px on the longer side), "files" (default) names each picture's file, "none" leaves them out. Touches no browser.

Inputs: ids, limit, filter, pictures. Returns: cards, total, missing, notABug

scout_clickA

Click an element by its ref from the latest scout_snapshot. Returns the outcome plus any oracle violations triggered. clicks=2 (or 3) probes IMPATIENT-USER behaviour: a rapid multi-click that fires the same state-changing request twice means the control is not guarded against double submission (button stays enabled, endpoint not idempotent) — use it on every important submit/create button once; the result says explicitly whether duplicates fired.

Inputs: ref (required), task, leave, clicks, +2 more.

scout_closeA

Close a session's browser (memory persists on disk). Default: the DEFAULT session. Pass session to close a specific one, or all=true to close every live session at the end of a multi-role run. A session that is a lane of a parallel run (named by scout_lane_brief or scout_lane_report) is not closed until its lane report has been accepted by scout_lane_report, since folding needs the session attached; the refusal names every such lane.

Inputs: all, force, session.

scout_coverageA

Show exploration coverage: states visited, which elements remain unexercised, which options of a dropdown used this run no session has chosen yet, and which forms seen this run no session has submitted with every text field blank. Use to decide where to explore next and when the level's budget is satisfied. In a parallel run it shows this session's own work by default — the routes it reached this run and the forms it saw — so one lane is not handed another's gaps; scope:"project" shows every session's, each form and route tagged with the sessions that saw it.

Inputs: scope, session.

scout_crawlA

Engine-side route sweep in ONE call: visits each path (default: all known routes not yet visited), records states into coverage memory, and returns a per-route health summary (HTTP status, element count, what the main area holds, oracle violations, dead-ends, auth-redirects, and ERROR-VIEW or STILL-LOADING for a main area showing only an alert or a loading placeholder). Navigation-only — safe in read-only mode. Use this FIRST for broad coverage; explore interactively only where it flags problems or where journeys matter.

Inputs: paths, session.

scout_criterionA

Record whether one acceptance criterion of a ticket read with scout_tickets passed, failed or was not tested, with how sure you are. The link from a criterion to the findings that show it is YOUR judgement, stated with a confidence — never matched on words. A "fail" names the findings that show it (file them with scout_finding first); "not-tested" says why in untestedBecause. Recording the same criterion again from the same session replaces your earlier verdict. Touches no browser.

Inputs: reason (required), ticket (required), verdict (required), criterion (required), +4 more.

scout_design_auditA

Computed-style design audit of the current page — a design connoisseur's read WITHOUT screenshots. Measurable defects (⚠): WCAG contrast, tiny targets, clipped text, aspect-distorted images, horizontal overflow, sibling cards touching with no gap (naming their parent), missing keyboard-focus indicators (sampled with real Tab presses). Craft suggestions (→): line measure and line-height rhythm, spacing-scale adherence, typography entropy, palette discipline (gray census, accent hue families, pure-#000 body text), elevation/control consistency, heading structure, indistinguishable links, and AI-slop tells (gradient text, glassmorphism, side-stripe borders, neon glows, violet gradients, identical card grids). Ends with a SYSTEM SUMMARY of design-system coherence and a PAGE SCORE whose why: line lists the largest deductions behind it; once four pages are audited, a SITE CONSISTENCY block sets this page's button heights, radii, headers, tabs and grays beside the other pages' and names the values only one page uses. Run once per representative page; the → tier is improvement feedback — file genuine opportunities as ux-polish findings with the concrete numbers, not just defects.

Inputs: session.

scout_feedbackLabel a findingA

Record the person's own verdict on a finding: "not-a-bug" or "confirmed", with their reason if they gave one (at most 300 characters). Call it only with what the person said; never label a finding yourself. The finding is kept either way, keeps its id, and a later filing of the same problem still merges into it; cards and the status pane list a not-a-bug one apart. export: true instead lists every label in the project as candidates for a maintainer to review: they never change an answer key or the dedup by themselves. Touches no browser.

Inputs: id, export, reason, verdict. Returns: verdict, findingId, candidates

scout_findingA

Record a structured finding (bug, UX issue, or improvement). Deduplicates across runs; automatically captures the recent action trace as the repro, and a picture of what it is about (the element ref names, else the viewport), kept for report.html and returned in this result as an image. Use for anything worth reporting: crashes, oracle violations you confirmed, dead ends, confusing UX, permission leaks, missing testids — and design-audit improvement opportunities (ux-polish) with their concrete measurements.

Inputs: title (required), detail (required), category (required), severity (required), +4 more.

scout_guided_confirmAsk the person to confirm a guided planA

Ask the PERSON, through a form this server shows them, whether a guided plan whose care level writes may start: May submit forms on a site that is not on this computer, or May create test data anywhere (which also asks them to type a code the form shows). You may make this call; you cannot answer it, and nothing you pass accepts a plan. The plan is accepted only when the person says yes in the form. When they decline, close it, go back, mistype the code, or this client cannot show forms, the plan stays unaccepted and the result says so: tell the person, and offer the same check in Look only. Never retry it on their behalf. Touches no browser.

Inputs: planId (required). Returns: mode, planId, outcome, accepted, +1 more

scout_guided_planBuild a guided planA
Read-only

Turn a person's guided choices into a plan in plain words: the write mode its care level is, what each area does and holds back, what to tell the person, the calls to make in order, and its time and page limits. Pass choices to build a new plan, or planId to read one already built (a panel builds it and hands you only the id). A plan whose care level writes on a site that is not on this computer, or that creates test data anywhere, is built unaccepted: scout_guided_confirm asks the person, and until they accept, scout_attach above observe is refused. Once any plan is built, every scout_attach above observe must name an accepted plan's planId. A care level above the SceneScout config's maxMode is refused. Touches no browser.

Inputs: planId, choices. Returns: mode, areas, calls, level, +8 more

scout_hoverA

Hover an element by ref like a user pausing the pointer on it, and report what it reveals: tooltips/popovers (diffed against pre-hover state), any other new page text that appeared (labelled as possibly unrelated on busy pages), the title attribute, and aria-describedby text — each item truncated to 300 chars. Hovering does not count as exercising the element. Use on badges, icons, truncated text, and error indicators BEFORE concluding an element 'does nothing' — hover-gated UI is invisible to snapshots and clicks.

Inputs: ref (required), session.

scout_intakeStart a guided checkA

Ask how the person wants their site checked when they gave no settings. Where this client can show a form, the person chooses there: the site's address, what to check, a journey or tickets, how they sign in, how careful to be and how thorough. This then builds a guided plan, asks the person to confirm it in a second form when its care level needs that, and returns the plan: what to tell them, then the calls in order. Otherwise, or when they decline or close the form, it returns four plain questions for you to ask in chat. Never asks for a password. Touches no browser.

Inputs: url.

scout_journeyA

Measure how EASY a real task is, not just whether it works — the question pass/fail e2e suites never answer. Wrap one user goal: scout_journey {action:'start', goal:'Create an order'}, perform it the way a first-time user would (navigate by CLICKING through the UI, not by jumping to a known deep URL — a shortcut invalidates the measurement), then scout_journey {action:'end', completed:true|false}. Returns interaction cost (clicks, navigations, distinct screens, elapsed), the actual path taken, and friction signals: BACKTRACKS (returning to a screen already left — the clearest sign the next step wasn't discoverable), screen count, and over-interaction. Run it on each module's primary journey; an abandoned journey is a high-severity finding.

Inputs: action (required), goal, note, session, +1 more.

scout_lane_briefA

For a run split across parallel agents (lanes). Divides the app's known routes between N lanes and returns each lane's session name, the objective to attach it with, and the routes it owns — whole modules per lane, balanced by route count, so no two lanes audit the same area and none is left unopened. Call it after the first crawl, when route knowledge is complete. Touches no browser; pass the briefs to your lane agents, then use scout_lane_report for what they hand back.

Inputs: lanes (required), goal, routes, fromRun, +4 more.

scout_lane_reportA

For a run split across parallel agents (lanes). Without reply: returns the paragraph to put in a lane's prompt, telling it to hand back ONE typed JSON object (verdicts, severities and categories from closed sets, a calibrated confidence per decision, routes covered, what blocked it). With reply: parses what the lane handed back and returns the one-line fold (defects, highs, unsure, mean confidence, routes) or the reason it was refused, to relay to the lane once. Touches no browser.

Inputs: lane (required), reply.

scout_loginA

Open a visible browser window for the USER to sign in to the app as a role, and save that sign-in for scout_attach { role }. Use it when an attach is refused because no sign-in is saved for the role, or the saved one has expired. Tell the user first, in plain words: "A browser window is opening. Sign in there as you normally would; it closes by itself once you are in." The window saves once the user is back on the app with a new session (a round trip through a single sign-on provider is followed, not taken for the end) and closes. Never type credentials into it yourself. Returns once signed in and saved, or after waitSeconds with the window still open: then call scout_login again with the same role to keep waiting. Closing the window saves nothing. Needs a desktop: on a machine with no display, ask the user to run scenescout login <url> --role <name> where they can see the window.

Inputs: url (required), role (required), browser, successUrl, +2 more.

scout_navigateA

Navigate to a path on the attached origin (e.g. '/orders') or a full URL on it. A path resolves from the origin's root, whatever page the session attached on. Also supports 'back' via scout_back.

Inputs: target (required), task, leave, session, +1 more.

scout_networkA

List the data requests (fetch and XHR) the current page made since its document loaded: method, path, status and time, oldest first, each marked with the route it was sent from when a client-side route change moved the page since. Use it when the page and the server seem to disagree — an empty list where the API has data, a stale value after a save — to tell a request that failed, one still pending and one that never ran apart. Read-only: it lists what the browser already saw and sends nothing. Credentials in query strings are redacted. A full page load starts a new list; scout_request's own calls are marked.

Inputs: limit, session, contains.

scout_noteA

Cumulative WRITTEN knowledge about the tested app — .scenescout/ASSUMPTIONS.md, in prose a human can read and correct. memory.json stores coverage; this stores UNDERSTANDING, so every run starts smarter than the last. READ it at the start of every session ({action:'read'}). ADD durable learnings as you go ({action:'add', section, note}): what the app is for (app-model), who each role is and what they're FOR — infer the persona from what the role can see and do, e.g. 'qa-role = reviewer: approves orders, cannot administer' (roles), UI patterns the app follows (conventions), rules discovered the hard way like 'an order can only ship once approved' (constraints), fragile areas worth re-testing every run (risks), domain terms (glossary), and how to get the app testable at all — the command that regenerates an expired login state, what has to be running (setup), which the engine reads back to you the next time a storage state has expired. Notes are dated, attributed to the acting role, and deduplicated. Do NOT record session-specific facts (ids, counts) — only durable knowledge.

Inputs: action (required), note, section, session.

scout_playbookA

Return the SceneScout testing method: setup order, write modes, how to explore, what counts as done, how to report. Call this ONCE before the first scout_attach in a conversation, then follow it. If this client offers a SceneScout skill, load that instead — it is the same text, so never read both. Takes no input and touches no browser.

Inputs: no named parameters.

scout_pressB

Press a keyboard key (e.g. Escape, Tab, Enter) — useful for closing modals and testing keyboard navigation.

Inputs: key (required), task, session, objective.

scout_recapEnd-of-check cardA
Idempotent

The recap of the guided check that has just ended, for the person to share with their team: the address, pages checked, problems found by impact, problems a re-check confirmed fixed, and the time it took. Returns it as an SVG picture and as lines of text; with save: true it is also written to the project's .scenescout/recap.svg. Built from the check's figures only. Refuses while no guided check has ended. Touches no browser.

Inputs: save. Returns: svg, date, file, rows, +3 more

scout_recheck_planPlan a re-check after a fixA
Read-only

Build a guided plan that checks again the problems earlier checks left open, and says which are gone, still there or changed. It runs in the care level the problems were found in, never a looser one: problems found in a looser care level are left for a re-check of their own, and problems on another site for a re-check of that site. It is a new plan: where its care level needs the person's confirmation, scout_guided_confirm asks them again, whatever an earlier check was given. Follow it as you would scout_guided_plan's: attach with its planId, then scout_verify. By default every open problem but those the person marked not a bug, worst route first, at most 25; pass ids for exactly those. Touches no browser.

Inputs: ids, signIn, address. Returns: mode, areas, calls, level, +8 more

scout_reportA

Generate the final markdown report — findings, page quality scores (worst first), role capability matrix, oracle rollup, and the GAP LEDGER (an explicit list of what was NOT tested). Writes the full document to .scenescout/report.md and returns a bounded SUMMARY (full reports exceed client token limits). Gates by level: 'minimal' needs all routes visited + ≥1 design audit; 'medium' additionally needs several routes audited; 'extensive' REFUSES while the gap ledger is non-empty — that refusal is the completeness guarantee: an extensive report only generates when nothing known is left untested. force=true overrides (only when the user capped the budget).

Inputs: force, level, report, history, +1 more.

scout_requestA

Call the app's own API as this session, with the UI bypassed — the check that turns a hidden or disabled control into a proven refusal. A button that is not shown proves nothing; the same action refused by the server does. The fetch runs IN the page, so it carries the session's cookies and replays the Authorization header the app itself last sent, and it passes through the same interception the write policy is enforced on: in safe-write a mutation on a record this session did not create is refused here exactly as it would be for a click, and that refusal is the engine's safety net, not a finding. Returns the status line, the timing, the headers that decide whether two responses are truly identical (content-type, location, www-authenticate, retry-after, cache-control), and the body — its first 2000 characters, or the part named by select (one JSON value by path) or offset/limit (a window of characters). Unlike a shell call, every request is recorded in the run's trail and its signature is what a finding should quote. Paths are fenced to the attached origin: use another session to reach another host.

Inputs: path (required), body, task, limit, +6 more.

scout_resolveA

Mark a finding as resolved (by its id, shown when recorded and in the report). Resolved findings move to the report's green ✅ Resolved section, and reopen automatically as flagged REGRESSIONS if re-found later. Use when the user says a bug is fixed, or when re-testing shows the evidence no longer reproduces.

Inputs: id, session, findingId.

scout_run_planA

Execute up to 20 actions in ONE call — use for mechanical sequences (fill a form, walk a wizard) so each step doesn't cost a round-trip. Targets resolve at execution time by semantic locator: 'testid=…', 'text=…', 'label=…' or 'role=button[name=Save]' (never snapshot refs). The same steps, saved to .scenescout/flows/.json with expect-text / expect-url / expect-request steps added, are replayed by scenescout check on every pull request. An upload step attaches a file as scout_upload does (target required — the file input or the control that opens its chooser; value = a fixture kind or a project-relative path). The plan ABORTS at the first NEW oracle violation, policy refusal, or failed step, returning a transcript of how far it got; repeats of already-reported violations do not abort (they stay logged for the report). For a sweep of independent steps (tabs, filters, pages) pass onViolation "continue": a new error status or its console echo is listed on its step's line and the plan goes on; a failed step, a policy refusal or any other violation still stops it. A select step whose value names no option fails at once, listing the options.

Inputs: steps (required), task, session, objective, +1 more.

scout_saved_checksThe person's saved checksA

List, save, run or delete the person's saved guided checks. A saved check keeps the choices of a guided plan under a name (the address, what to check, the journey, how they sign in, the care level and how thorough), never a password, code, token or cookie, in the project's .scenescout/guided/ folder, readable by its owner only. "save" takes a name and the planId of a plan built from choices (a re-check is not saved). "run" builds a new plan from a saved check, unaccepted: where its care level needs the person's confirmation, scout_guided_confirm asks them again. Follow that plan as scout_guided_plan's. "delete" removes one saved check's file and nothing else. With no check open in this conversation, pass the site's address so SceneScout finds its folder. Touches no browser.

Inputs: action (required), name, planId, address. Returns: plan, saved, folder, refused

scout_scanA

Scan a project directory to discover the frontend workspace, framework, routes, dev command, Playwright auth storage states, and testid conventions. Run this first.

Inputs: projectPath (required).

scout_screenshotA

Take a JPEG screenshot of the current viewport. LAST RESORT: geometry issues are in scout_snapshot and style/contrast/spacing issues are in scout_design_audit — images that failed to load are listed in scout_snapshot under BROKEN IMAGES — use a screenshot only for pixel-native content (a canvas, visual gestalt) that computed data cannot capture.

Inputs: session.

scout_scrollA

Scroll like a user — real apps hide their bugs below the fold. Reports the resulting position (px and %), and explicitly flags SCROLL LOCKED: scrollable content exists but the page will not move (the classic leaked modal scroll-lock that silently cuts users off from everything below the fold — snapshots also detect this passively as an OVERLAY line). Without target it scrolls the page, falling back to the largest scrollable pane on app-shell layouts. Pass target to scroll ONE region instead (a sidebar nav, a dialog body, a table pane): the page-level pick is the LARGEST scroll port, so a smaller region beside it never moves and its content looks truncated when it is only scrolled away — never call a nav item missing without scrolling its own container first. Use before judging a long page: the design audit measures at the current scroll position, so scroll + re-snapshot/re-audit deep sections; scroll also triggers lazy-loaded content whose failures then surface as oracle violations.

Inputs: by, to, target, session.

scout_selectA

Select an option in a by ref. The value is matched against the options before anything is picked: an exact value, an exact label, either ignoring case, then a label it starts with. A value matching no option, or several, is refused at once with the options listed.

Inputs: ref (required), value (required), task, session, +1 more.

scout_sessionA

List live sessions, or set which one is the DEFAULT (used by any tool call that omits session). Prefer passing session directly on each tool call for multi-role work — that's what lets concurrent dispatch happen; scout_session is for sequential convenience (skip repeating session on every call) and for checking what's live. Both browsers stay live and authenticated regardless of which is default — re-snapshot a session after a break to see what changed while it was away.

Inputs: area, name, paceMs, session.

scout_snapshotA

Capture the current page state: URL, state fingerprint, a one-line summary of the main area's heading and text, interactable elements with refs (e1, e2, …) and their state (pressed, selected, checked, expanded, current), what the page announces (alert and status regions, by their text), geometry issues, coverage, and oracle violations since the last action. Re-snapshotting a route returns a DIFF against its last snapshot, even after visiting elsewhere, and another tab of the same screen diffs against that screen's last tab; refs stay stable, including across a search or filter that rewrites only the query string. On a dense page, says what past the element cap was cut. Cheap — prefer this over screenshots.

Inputs: full, session.

scout_statusRun statusA

Show the person running you how the run stands: each session's objective and current task, open findings by severity, coverage, and the live view's address. In a guided check it also shows the check's progress in plain words: what is happening now, each area's state, pages and time against the plan's limits, problems so far and the newest cards, and the clicking it saved with what that figure is based on. Call it when the user wants to watch or asks how the run is going. A host that renders MCP Apps shows a pane that keeps itself up to date; every other host gets the same as text, and you pass the Live view: address on. Takes no input and touches no browser.

Inputs: no named parameters.

scout_status_pollRun status (for the pane)A

Called by the scout_status pane every few seconds to refresh itself. Not for the agent: call scout_status instead.

Inputs: no named parameters.

scout_team_reportMake a team reportA
Idempotent

Write the team report: the plain report made for sharing, as one page that opens in any browser. It has a cover (the site, the date, what was checked, the care level and how thorough), a short summary, each problem this check found as a plain card with its picture, the ones the person marked not a bug listed apart, what the check did not test, and blank sign-off lines. Beside it, an evidence folder holds the pictures, the report as Markdown and manifest.json with every file's SHA-256, the SceneScout version and the check's times. Writes only inside the project's .scenescout/ folder (team-report.html and team-report/), replacing the last team report; sends nothing anywhere and touches no browser. Tell the person where the page is.

Inputs: no named parameters. Returns: file, path, folder, manifest, +4 more

scout_ticket_fileFile previewed ticketsA

File the tickets a preview from scout_ticket_preview listed. Before anything is sent, this server asks the PERSON in its own form, listing the tickets; it files only on their yes there. You may make this call; you cannot answer the form, and nothing you pass confirms it. It files only the previewed problems, only while the preview is under 10 minutes old and only if those problems have not changed since; otherwise it refuses and a new preview is needed. A preview is used once: after the person goes back, turns the form down or closes it, or this client cannot show forms, nothing is filed: tell them, and never call it again on their behalf. Returns each filed ticket's link. Touches no browser.

Inputs: previewId (required). Returns: filed, outcome, tickets, problems, +1 more

scout_ticket_previewPreview problems as ticketsA
Read-only

Preview filing the problems the person chose as GitHub or Jira tickets. Reads the tracker to find which are already filed (by the marker scenescout export writes) and sends nothing. Returns each ticket that would be filed, the ones already filed, any over the limit of one filing, and a previewId that lasts 10 minutes. Show the person the list; to file it, call scout_ticket_file with the previewId. to: "github" with target the repository as owner/name, or "jira" with target the project key (the Jira site is JIRA_BASE_URL in the server's settings). The tracker's sign-in comes from the server's environment or the desktop extension's settings only (GH_TOKEN or GITHUB_TOKEN; JIRA_EMAIL and JIRA_API_TOKEN): never ask the person for a token and never pass one. Touches no browser.

Inputs: to (required), ids (required), target (required). Returns: to, cap, later, where, +6 more

scout_ticketsA

Read the tickets or acceptance criteria the person gave this run, pasted (text) or from a file (path), and keep them so the report answers each criterion: passed, failed or not tested. Recognises Given/When/Then scenarios, checklists, numbered and "AC1:" criteria, and lists under an "Acceptance criteria" heading; several tickets may be given at once. A ticket with no recognisable criteria is reported as such, never guessed at. Returns each criterion's id (AC1, AC2, …) to judge it by with scout_criterion. Touches no browser.

Inputs: path, text, session.

scout_ticket_statusRead filed tickets' stateA
Read-onlyIdempotent

List the tickets this project filed (with scout_ticket_file or scenescout export) and whether each is still open in GitHub or Jira, with whether its problem is still open in this project. Reads each tracker at most once every 5 minutes per project; a call sooner answers what the last read found (fresh: false, with when the next read is due). Only a tracker the server's settings point at is read, with the sign-in from its environment. Sends nothing but reads; touches no browser. With no check open in this conversation, pass the site's address so SceneScout finds its folder.

Inputs: address. Returns: fresh, readAt, tickets, problems, +1 more

scout_typeA

Type into a text input/textarea/composer by ref, the way a real user does: if the field already holds content (e.g. an @-mention chip a menu click inserted), the text is APPENDED at the end — preserving that content — and the result reports what was already there (a separating space is added only at a word-to-word boundary). Pass replace=true to clear the field first (correcting a previous entry); an empty textValue always clears. Appending fires input events but not keydown, so keydown-driven triggers (slash/mention menus) will not react to appended text. Use for both valid values and boundary/fuzz values (empty, very long, unicode, script tags). A value typed into a secret field (a password, a one-time code, a card number, a field labelled secret or token) is masked in the result and the log, as is what the field held.

Inputs: ref (required), task, value, replace, +4 more.

scout_uploadA

Attach a file to an upload control the way a user does. ref is either a visible (snapshots list these with role file) or the button/label/dropzone that opens the file chooser — the chooser is intercepted and answered, which is how the hidden input behind a styled 'Choose file' control is reached. Omit ref to target the page's only file input, hidden or not (snapshots disclose hidden ones on a FILE INPUTS line). Nothing needs to exist on disk: a small VALID fixture (real PDF/PNG structure) is generated in memory, its kind inferred from the input's accept attribute or chosen with fixture; filePath uploads a real file but must live inside the attached project (fenced like navigation is fenced to the origin), and a credential-shaped one (a dotfile or anything in a hidden folder, .env*, an SSH key, *.pem/*.key/*.p8/*.p12/*.pfx/*.ppk/*.jks/*.keystore/*.asc/*.kdbx, anything under .ssh, .aws, .gnupg, .config, .kube or .docker) is refused unless the operator listed it; name overrides the filename for boundary tests (wrong extension vs accept, very long, unicode). The result names the input, how the file reached it, flags a file that violates accept (a mismatch the app then accepts is a validation finding), warns if the app cleared the input after selection, and says whether a state-changing request fired on selection — if none did, click the form's submit, or check the next snapshot for a client-side rejection.

Inputs: ref, name, task, fixture, +3 more.

scout_verifyA

Re-test findings earlier runs left open. With no arguments, returns the open findings in the order to re-test them — worst route first, grouped so a route is walked once — each with its evidence and repro steps. Pass ids to narrow it to specific findings. After re-testing one, call again with id and verdict to record what you saw: "gone" resolves it, "present" stamps it confirmed so the report stops calling it unverified, "changed" keeps it open and says the behaviour differs. Use after a fix wave, or at the start of a run against an app this project has tested before.

Inputs: id, ids, note, session, +1 more.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.6/5.0

    Scored across 48 tools

    Disambiguation3/5

    Core interaction tools (click, type, select, press, hover, scroll, navigate, back) are cleanly separated, and the finding-lifecycle tools (finding, cards, feedback, resolve, verify) are distinguishable. But the planning surface — scout_intake, scout_guided_plan, scout_guided_confirm, scout_recheck_plan, scout_saved_checks, scout_lane_brief/report — and the four reporting tools (report, team_report, recap, cards) overlap heavily in intent; only very long descriptions keep them apart. scout_run_plan vs. the single-action tools is another soft overlap an agent could misselect on.

    Naming Consistency4/5

    Every tool uses the scout_ prefix and snake_case, with a predictable verb_noun or resource_noun shape. Minor deviations (noun-only names like scout_playbook, scout_journey, scout_recap, scout_coverage) break the verb pattern but remain readable and unambiguous within the prefix scheme.

    Tool Count2/5

    48 tools is well past the 'heavy' band and sits in the too-many range for a single server. Much of the bulk comes from peripheral surfaces (guided plans, saved checks, lanes, ticket filing/status, three report formats) that could be consolidated or split into separate servers.

    Completeness4/5

    The surface is unusually thorough for browser-based QA: interaction, network, design audit, journeys, coverage, findings with dedup/verification, guided plans, and reporting are all present with lifecycle coverage. Gaps are minor — no explicit console-log retrieval, viewport/device emulation, or waiting/synchronization primitive — which agents can mostly work around.

    Maintenance

    ActivityNo data
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      B
      maintenance
      MCP server that provides AI coding agents with real-time visual access to web apps, enabling them to see screens, run accessibility and layout inspections, and interact with pages through a shared live panel.
      95 npm
      130
      MIT