Install
$ agentstack add mcp-0xjesus-screenwright β scanned Β· β verified, works with Claude Code, Cursor, and more.
Security review
β PassedNo issues found. Passed automated security review. Β· v0.1.0 How review works β
- β Prompt-injection patterns
- β Secret / credential exfiltration
- β Dangerous shell & filesystem operations
- β Untrusted network calls
- β Known-malicious package signatures
What it can access
- β Network access No
- β Filesystem access No
- β Shell / process execution No
- β Environment & secrets No
- β Dynamic code execution No
From automated source analysis of v0.1.0. βUsedβ means the capability is present in the source β more access means more to trust, not that itβs unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work βAbout
π¬ Screenwright
> Subtitled tutorial videos, scripted. An MCP server that turns a list of steps into a narrated screen recording β by driving a real browser (Playwright) or an Android / Flutter emulator (adb). Captions are burned into the video and exported as an .srt.
The name is a play on Playwright (the engine under the hood) + screen.
steps[] βββΊ Playwright drives the browser βββΊ caption overlay synced per step
βββΊ video recorded βββΊ ffmpeg β .mp4 + .srt sidecar
β¨ Features
- Scripted walkthroughs β
goto,click,fill,type,press,hover,scroll,wait. - Synced subtitles β attach a
captionto any step; it's burned into the video and written to a timed.srt. - Real voice-over (optional) β turn captions into a spoken narration with ElevenLabs or OpenAI TTS. Each line is pre-synthesized and the screen is held while it plays, so audio stays perfectly synced to the subtitles. Configure once via env.
- Self-contained output β bundled
ffmpeg(viaffmpeg-static) produces a clean H.264.mp4. - Robust β per-action timeouts; mark a step
optionalso a missing selector doesn't abort the take. - **Web and mobile β Playwright for the web;
adbscreen-record + ffmpeg caption-burn for Android / Flutter** apps (no app source needed). - Use it from an AI (MCP tool) or straight from Node.
π¦ Requirements
- Node.js 18+
- A Chromium build for Playwright:
npx playwright install chromium(run automatically onnpm install).
π Install
# from GitHub
npm install -g github:0xjesus/screenwright
# or clone
git clone https://github.com/0xjesus/screenwright.git
cd screenwright && npm install
π Use as an MCP server
Add it to your MCP client. Claude Desktop / Claude Code (claude_desktop_config.json or .mcp.json):
{
"mcpServers": {
"screenwright": {
"command": "node",
"args": ["/absolute/path/to/screenwright/src/index.js"]
}
}
}
(If installed globally, you can use "command": "screenwright" with no args.)
Then just ask your assistant to record a tutorial β it calls the record_tutorial tool.
Tool: record_tutorial
| Field | Type | Notes | |---|---|---| | output | string | Path to the output .mp4. | | steps | step[] | Ordered steps (below). | | baseUrl | string? | So goto steps can use relative paths. | | viewport | {width,height}? | Default 1440Γ900. | | headless | bool? | Default true. | | channel | string? | e.g. "chrome" to use the system browser. | | burnIn | bool? | Burn captions into the video. Default true. | | srt | string? | Custom .srt path. Default .captions.srt. | | tts | object? | Voice-over β see [ποΈ Voice-over](#οΈ-voice-over-tts). | | captionStyle | object? | { position, fontSize, bg, color, maxWidth }. |
Step = { caption?, narration?, action, url?, selector?, text?, key?, deltaY?, delayMs?, timeoutMs?, dwellMs?, optional? }. selector is any Playwright selector β CSS, text=β¦, xpath=β¦, or :has-text(β¦).
Tool: record_android_tutorial π±
Same idea, for a Flutter / Android app on an emulator or device. Captions can't be injected into a native app, so the screen is recorded with adb screenrecord and the captions are burned in afterwards with ffmpeg (libass) from the synced .srt.
Requires: Android platform-tools (adb) + a running emulator/device (it must show in adb devices). For Flutter: flutter emulators --launch , then run your app.
| Field | Notes | |---|---| | output | Output .mp4. | | steps | Ordered steps (below). | | serial | adb -s serial when several devices are connected. | | size | Recording size "WxH" (default: device resolution). | | bitRate Β· srt Β· burnIn Β· adbPath Β· captionStyle | Optional. | | tts | Voice-over β see [ποΈ Voice-over](#οΈ-voice-over-tts). |
Step actions (coordinates are device pixels) β each may carry a caption and dwellMs:
tapβ{ x, y }textβ{ text }swipeβ{ x1, y1, x2, y2, durationMs? }keyβ{ key }(BACK,HOME,ENTER,MENU,APP_SWITCH, or aKEYCODE_*)launchβ{ package, activity? }waitβ{ dwellMs }
See examples/android-flutter.json. From Node: import { recordAndroidTutorial } from 'screenwright/android'.
ποΈ Voice-over (TTS)
Turn your captions into a real spoken narration β same tool, both drivers (web + Android). Provider and voice are set once via env (the same MCP config), so any record_* call with captions gets narrated automatically. Each line is synthesized before recording and the screen is held while it plays β the voice stays locked to the burned-in subtitles.
Configure in your MCP server env (or shell):
{
"mcpServers": {
"screenwright": {
"command": "node",
"args": ["/absolute/path/to/screenwright/src/index.js"],
"env": {
"SCREENWRIGHT_TTS_PROVIDER": "elevenlabs",
"ELEVENLABS_API_KEY": "sk_...",
"ELEVENLABS_VOICE_ID": "21m00Tcm4TlvDq8ikWAM",
"ELEVENLABS_MODEL": "eleven_multilingual_v2"
}
}
}
}
OpenAI instead: SCREENWRIGHT_TTS_PROVIDER=openai, OPENAI_API_KEY=..., OPENAI_TTS_VOICE=onyx, OPENAI_TTS_MODEL=gpt-4o-mini-tts.
Per-call override (wins over env), plus a narration field when the spoken line should differ from the on-screen caption:
await recordAndroidTutorial({
output: 'out/tour.mp4',
tts: { provider: 'elevenlabs', voiceId: 'β¦', speed: 1.0, stability: 0.5 },
steps: [
{ action: 'launch', package: 'com.acme.app', caption: 'Meet Acme', narration: 'This is Acme β your market copilot.', dwellMs: 1500 },
{ action: 'tap', x: 540, y: 1925, caption: 'Generate a signal', dwellMs: 1000 },
],
});
// β { mp4, srt, durationMs, steps, captions, narration: { provider, lines } }
ttsfields:provider(elevenlabs|openai),apiKey?,voiceId?/voice?,model?,speed?,stability?,similarityBoost?,style?,tailPadMs?(silence after each line, default 450).- Requires the bundled
ffmpeg(already a dependency) to mix + mux the audio. Multilingual voices (e.g.eleven_multilingual_v2) narrate Spanish/English captions cleanly. - No
ttsand no env provider β silent captions, exactly as before.
π§ͺ Use from Node (no MCP)
node scripts/run-example.js # records examples/demo.json
node scripts/run-example.js examples/capleton.json
import { recordTutorial } from 'screenwright/recorder';
await recordTutorial({
output: 'out/tour.mp4',
baseUrl: 'https://playwright.dev',
steps: [
{ action: 'goto', url: '/', caption: 'Welcome to the tour π¬', dwellMs: 2600 },
{ action: 'scroll', deltaY: 600, caption: 'Each step can carry a synced subtitleβ¦', dwellMs: 2400 },
{ action: 'goto', url: '/docs/intro', caption: 'β¦burned into the video and exported as .srt', dwellMs: 3000 },
],
});
// β { mp4, srt, durationMs, steps, captions }
π‘ Tips
- Don't double your subtitles. The
.mp4already has burned-in captions. Players like VLC auto-load an.srtthat shares the video's name and draw it on top. Screenwright defaults the sidecar to*.captions.srt(a non-matching name) so that doesn't happen β keep it that way, or disable the subtitle track in your player. Want selectable-only subs? PassburnIn: falsefor a clean video + the.srt. - Black video in VLC on Linux? That's a GPU/output glitch, not the file. Launch with
vlc --avcodec-hw=none --vout=xcb_x11, or set those in VLC β Preferences. - Headless still records β no display needed.
π License
MIT Β© 0xjesus
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source β we do not rehost the code.
- Author: 0xjesus
- Source: 0xjesus/screenwright
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.