video-qa
Records and analyzes web application sessions in Google Chrome, capturing visual changes and timelines for testing.
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., "@video-qaRecord the browser while I test the checkout flow, then analyze it."
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.
Flipbook
Claude can't watch video. Flipbook records your web app while Claude drives it and hands back a flipbook it can read: a labelled contact sheet, full-resolution key frames, and a timeline correlated with the actions that caused each change.
For Claude Code on macOS 15+. Works alongside Claude in Chrome without interfering with it.
The problem
Claude in Chrome validates web apps with discrete screenshots. Everything between two screenshots is invisible — spinners, layout shift, flicker, double-submits, and toasts that appear and vanish. A before/after pair can't tell "it worked" from "it worked eventually, badly".
This isn't hypothetical. Driving the bundled test fixture, Claude in Chrome's own screenshot shows:
Order checkout
Idle.
┌─ Order confirmed ─────────────┐
│ Item Widget Pro │
│ Quantity 3 │
│ Total $147.00 │
└───────────────────────────────┘Looks like a pass. But the run also showed a two-second loading spinner and a "Saved successfully" toast — and both are missing, because the toast had already disappeared by the time the screenshot was taken.
Flipbook records the same run and returns this instead — one image, the whole timeline:

Every cell is labelled with its frame number and timestamp, red outlines mark the largest visual changes, and the caption says why each frame was chosen. The spinner (02–04) and the toast (05, top right) are exactly what the screenshot above missed.
That image is real output, not a mockup — regenerate it with node scripts/make-demo.mjs.
gif_creator doesn't close this gap: it stitches together screenshots Claude already took
and exports them for a human, returning nothing to the model. And the vision API reads only
a GIF's first frame, so an animated GIF isn't something Claude can watch either. (Hand
one to analyze_recording and Flipbook will decode every frame of it.)
Related MCP server: Screenshot Website Fast
Install
Before you start: macOS 15+ (window capture uses ScreenCaptureKit), Node 22+, Xcode
Command Line Tools (xcode-select --install), and Google Chrome.
1. Add the marketplace and install.
claude plugin marketplace add ShubhenduVaid/flipbook
claude plugin install flipbook@shubhenduvaid2. Grant Screen Recording to your terminal — System Settings → Privacy & Security → Screen & System Audio Recording — then restart the terminal. This is the one step nothing can do for you, and the one most worth getting right: without it macOS records a blank screen rather than erroring, so a recording looks like it worked and contains nothing.
3. Start Claude and run doctor.
claude --chromeThen ask Claude to run doctor. It finishes setup on first run — compiling the
ScreenCaptureKit recorder and restoring the bundled ffmpeg binary, which Claude Code's
installer skips because it installs plugin dependencies with --ignore-scripts — and it
checks every prerequisite above, including the permission from step 2.
You're ready when doctor says so. Warnings are fine; failures are not.
4. Record something — see Usage below.
claude plugin list # name, version, scope, enabled
claude plugin details flipbook # what it contributes, and its token costgit clone https://github.com/ShubhenduVaid/flipbook && cd flipbook
npm install
npm run build:native # compiles the ScreenCaptureKit recorder
npm run doctor # preflight every prerequisite
claude --chrome --plugin-dir "$PWD"--plugin-dir loads the plugin for one session only, and takes precedence over an
installed copy — handy for trying a change without disturbing your install.
Updating
Two steps, because they do different things: the first refreshes the catalogue, the second installs from it. Doing only the second is the usual reason an update appears to do nothing.
claude plugin marketplace update shubhenduvaid # fetch the latest catalogue
claude plugin update flipbook # install itRestart Claude Code afterwards. A running session keeps the version it started with.
Then run doctor once in the new session. It recompiles the native recorder if the plugin
shipped a new one, so a version that changes the recorder is fixed by the same command that
diagnoses everything else.
claude plugin list # confirm the new versiongit pull
npm install # in case dependencies changed
npm run build:native # in case the recorder changed
npm run doctorVersion unchanged in
claude plugin list— the marketplace catalogue is stale. Runclaude plugin marketplace updatewith no name to refresh every marketplace you have.New tools or parameters missing — the session predates the update. Restart Claude Code; tool schemas are read once at startup.
Recording fails or returns nothing after an update — run
doctor. A recorder compiled against an older plugin is its most likely cause, anddoctorrebuilds it.Still wrong — reinstall cleanly:
claude plugin uninstall flipbook claude plugin install flipbook@shubhenduvaidYour recordings live in
~/.flipbookand are untouched by this.
Versions follow semver. Released versions are tagged
flipbook--v<version>, so the tag list
is the changelog — each annotated tag says what changed and why.
Usage
/flipbook:record the checkout flow shows a spinner, then a confirmation, and no errorsOr just ask — the bundled skill tells Claude when to reach for this. Under the hood:
start_recording— begins capturing the browser windowyou or Claude drive the app; every Claude-in-Chrome action is timestamped automatically
stop_recordingwith a rubric — what "working correctly" means, one criterion per lineClaude judges the evidence and cites frames
A rubric should be observable in pixels and time:
A loading indicator appears within 500ms of clicking Submit.
The loading indicator disappears once results render.
No error toast appears at any point.
The layout does not shift after the results render.And the verdict cites evidence you can check:
No error toast appears — FAIL. Frame 06 at t=5.25s shows a toast reading "Saved successfully"; it's gone by t=6.75s, which is why the final screenshot looks clean.
Flipbook returns evidence, never a verdict. A tool that answers "PASS" hides its reasoning and can't be argued with.
Three ways to record nothing
Each produces a plausible-looking recording that contains no evidence. All were found the
hard way; doctor warns about the first two.
Recording a window whose active tab isn't the one under test. A window paints only its active tab, and Claude in Chrome will happily drive a background tab. Switch to it first.
Recording a window that another window covers. macOS marks it occluded and the browser stops painting it, so you capture frozen browser chrome over a blank page. Two browser windows at nearly the same position are the usual culprit. Behind a full-screen terminal on a different Space is fine; underneath another window on the same Space is not.
Taking a screenshot with size arguments while recording. That overrides the browser's device metrics, so the page repaints into a smaller viewport — or stops painting — while capture keeps rolling at the old size. This one is worse than the other two, because the result isn't blank: it's convincing evidence of a bug that doesn't exist. One reported run showed an 11-second blank load that a control run rendered in ~1.8s. The analysis detects the geometry change and says so.
When actions were recorded but the pixels didn't move, the analysis says so rather than letting you report a false pass. Same for a span between two marks where nothing changed, and for a subject too small in frame to read.
Tools
Tool | Purpose |
| Preflight: macOS, ffmpeg + filters, native helper, permission, target window, disk, footprint |
| Capture a window ( |
| Annotate the timeline mid-run, and split the per-segment change stats |
| Stop, analyse, return the evidence against a |
| Same analysis for any |
| Full-resolution drill-down at exact timestamps, over a range, or relative to a mark ( |
| Browse past sessions, with sizes and total footprint |
| Reclaim disk — a dry run unless |
analyze_recording accepts recordings you made yourself — hand it a QuickTime capture of a
bug you can't reproduce on demand.
Framing: roi
An image costs the same whatever it contains, so a small subject in a large window spends
most of its resolution on nothing. roi takes a fractional rect or "auto" — which derives
the region from the pixels that actually changed — and applies to the three tools above.
When the subject is small and no roi was given, the analysis says so and quotes the exact
rect to pass.
A cropped frame is announced four ways: a CROPPED VIEW header line, a [CROP …] prefix on
every caption, an amber border and badge burnt into every cell, and a roi object in
structuredContent that is present whether or not it applied. A crop read as the whole page
is exactly the failure mode the geometry detector exists to catch, so it's worth repeating.
Why stills instead of video
There's no video input, animations are explicitly unsupported, and the MCP spec has no
video content type (checked in both 2025-06-18 and 2026-07-28). So a recording has to
become stills plus text.
The budget was read out of Claude Code's own accounting rather than guessed:
Cost per MCP image | flat 1600 tokens |
MCP output budget | 25,000 tokens ( |
Never-truncated zone | 50% of budget → ~7 images |
Default output is 6 images — one contact sheet plus five detail frames — leaving room for
the timeline under the ~12,500-token ceiling. get_frames provides drill-down rather than
spending more images up front. A measured run comes in at ~10,100 tokens.
Keyframe selection samples at 128×128 and scores each frame both globally and per-block, because a 64px spinner in a 3000px-wide window moves the whole-frame average by 0.0003 — indistinguishable from noise. Dedupe compares pixels rather than perceptual hashes, which measured zero Hamming distance between an idle page and the same page showing a spinner. When two frames are identical, the earlier one wins, so the moment a state was reached isn't discarded in favour of an identical later frame.
Why ScreenCaptureKit
Display capture records whatever is visually on top — which is your terminal, not the
browser. Since the whole point is recording a browser Claude drives in the background,
window capture is the only approach that works. It also removes retina scaling and crop
arithmetic, and never captures anything but the target window. ffmpeg still does all the
analysis, and display capture remains available via target: "display".
Development
npm run validate # score the repo against docs/VALIDATION-RUBRIC.md
npm run validate -- --full # …including the criteria that need macOS + Chrome
npm test # 163 unit tests, no browser or permission needed
npm run lint # Biome (via npx — deliberately not a dependency)
npm run lint:manifests # plugin/marketplace/package manifests agree
npm run test:mcp # 36 MCP protocol checks (macOS)
npm run test:e2e # fixture: spinner + transient toast must be captured (macOS + Chrome)
npm run test:e2e:occluded # same, with the browser occludeddocs/VALIDATION-RUBRIC.md is the standard this project holds
itself to — 38 numbered criteria covering the promises this README makes, naming, security,
quality and docs. npm run validate is its executable form and reports each criterion
individually; there is no aggregate score, because a percentage would let a security failure
be averaged away by passing style checks. docs/ARCHITECTURE.md
explains the pipeline and what each module owns.
npm run validate, npm test and the linters run in CI on every push; the rest need macOS,
Chrome and Screen Recording permission, so they're local checks.
Cutting a release
Users get a new version by the two commands under Updating, which read the
marketplace manifest on main. So a release is: bump, verify, tag.
Bump the version in all four places —
package.json,package-lock.json(both the root andpackages.""),.claude-plugin/plugin.jsonand.claude-plugin/marketplace.json. Semver: a new tool or parameter is a minor, not a patch.npm run lint:manifestsfails if they disagree, and rubric criteria N1 and N3 cover exactly this.Verify, including the checks CI can't run:
npm run validate && npm run test:mcp && npm run test:e2e claude plugin validate . --strictTag it, once the bump is merged to
main:claude plugin tag --dry-run # check what it would produce claude plugin tag -m "flipbook %s" --pushclaude plugin tagcreates the{name}--v{version}tag this project uses, and refuses ifplugin.jsonand the marketplace entry disagree or the tree is dirty — which is why step 1 is worth doing properly. Tag messages are the changelog, so write them for someone deciding whether to update.
Biome is invoked through npx rather than added as a devDependency: Claude Code installs
plugin dependencies without --omit=dev, so a devDependency would ship into every user's
plugin cache. The formatter is off — the linter catches real defects, while reformatting
would churn deliberately aligned ffmpeg argument lists.
FLIPBOOK_DEBUG_SELECT=1 traces every keyframe accept/merge decision to stderr, which is
what threshold tuning needs.
Variable | Purpose |
| Data directory (default |
| Use a specific ffmpeg binary |
| Trace keyframe selection |
.claude-plugin/ plugin + marketplace manifests
commands/ /flipbook:record
hooks/ PostToolUse hook correlating Claude-in-Chrome actions
native/sckrec.swift ScreenCaptureKit window recorder
skills/ when and how Claude should use this
src/env/ ffmpeg, native helper, Chrome, doctor, paths
src/capture/ session lifecycle, recorder processes, prune policy
src/analyze/ sampling, delta scoring, selection, segments, capture anomalies,
region of interest, sheet, budget, timeline, clips
src/tools/ MCP tool definitions and shared parameter schemas
test/unit/ CI-safe unit testsRecordings are written to ~/.flipbook/sessions/ — outside your project, never
auto-uploaded anywhere.
License
MIT © Shubhendu Vaid
This server cannot be installed
Maintenance
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
- Flicense-qualityDmaintenanceEnables Claude to see and interact with any macOS application using natural language commands. Perfect for testing Mac applications, UI automation, and app development with AI assistance.Last updated32
- Alicense-qualityDmaintenanceCaptures high-quality screenshots and screencasts of web pages, automatically tiling full pages into 1072x1072 chunks optimized for Claude Vision API and other AI vision models.Last updated29326MIT
- Alicense-qualityCmaintenanceEnables Claude to remember and search everything that appeared on your screen using local OCR and embeddings. Provides tools for semantic search, activity timeline, and code change tracking.Last updatedMIT
- Alicense-qualityBmaintenanceEnables AI coding agents to capture screen and voice recordings, extract timestamped frames, and receive structured Markdown reports with context for bug fixing and UI feedback.Last updated2218MIT
Related MCP Connectors
Browser-backed QA with evidence and fix-ready reports for coding agents.
AI-powered browser automation — navigate, click, fill forms, and extract data from any website.
Persistent context for Claude. Your AI always knows your projects and next actions across sessions.
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/ShubhenduVaid/flipbook'
If you have feedback or need assistance with the MCP directory API, please join our Discord server