tourwright
Can use Ollama-hosted AI models to rewrite tour narration from captured screens.
Supports OpenAI and OpenAI-compatible TTS servers, and can use OpenAI models to rewrite tour narration from captured screens.
Provides a Redis/BullMQ-backed job queue for scaling Tourwright render jobs across API replicas and workers.
Scripted, narrated product tours. Write what should happen on screen and what should be said; Tourwright
films a real browser (or builds slides), guides the eye to each element, synthesizes the voice, and delivers
an .mp4 with captions, chapters, subtitles and a thumbnail. Built for people and AI agents, on any server, from a laptop to a cluster.
# tour.yaml
title: Your first invoice
voice: lessac
baseUrl: https://app.example.com
steps:
- goto: /invoices/new
- title: { text: Your first invoice, subtitle: Step by step }
- say: Pick the <b>customer</b> first.
- click: { role: combobox, name: Customer }
- say: Then save. That's it.
- click: { role: button, name: Save }tourwright render tour.yaml # → videos/tour.mp4 (+ .srt .vtt .jpg .json)Why Tourwright
Screen recorders (Loom) and click-through demo tools (Arcade, Supademo, Scribe) need a person to record, and every redesign means recording again. Tourwright videos are code:
Screen recorder | Demo SaaS | Tourwright | |
Re-record after a UI change | by hand | by hand |
|
Knows when a video went stale | no | no |
|
Narration | your voice, retakes | none or extra | text-to-speech in many voices, offline or online |
Same tour for 50 customers or languages | 50 recordings | 50 demos | one script with |
Personal data on screen | edit it out | edit it out |
|
Lives in | a vendor's cloud | a vendor's cloud | your git repo, your servers; MIT |
AI agents can make one | no | no | MCP server and a Claude Code plugin |
Related MCP server: Agent Demo Studio
What you get
Browser walkthroughs: real Chromium, a smooth animated cursor, click ripples, highlights, spotlights, callout bubbles, camera zoom, drag and drop, blurred personal data, title cards and captions in your colors and logo.
Guided focus: the tour an app shows the first time you open it. Everything dims but the element, a ring marks it, a bubble with a
2/4badge explains it and the camera pushes in, right on the word the voice is saying.Narrated slides: title cards, images (with slow pan/zoom), HTML, crossfades. No website needed.
Voices, your choice: Pocket TTS (offline, open, natural:
tourwright install --pocket), Piper (offline, open source, light), Microsoft Edge neural voices, any OpenAI-compatible TTS server (OpenAI, Kokoro, LocalAI…), or your own command. Every sentence is cached: re-rendering never re-synthesizes.A cast, and how each line is said: several voices per video, speed, pitch and volume per line on any engine, exact pauses (
[[1s]]), a pronunciation dictionary, sound presets (warm, radio, podcast…), click, typing and other sound effects, music with fades.Scripts that scale with you: variables (
{{name}}, also from the CLI or the API), reusable blocks, repeats, conditions and steps that may fail. One script, many videos.Plugins: new actions, TTS engines and voices as small modules (docs/PLUGINS.md).
Tight edits, automatically: page loads, slow waits and voice synthesis are cut out; narration never overlaps; background music ducks under the voice.
Deliverables: H.264/AAC
.mp4with soft subtitles and chapters,.srt,.vtt, thumbnail and a JSON manifest (duration, chapters, captions) for automation.Four ways in: CLI, HTTP API with job queue and webhooks, MCP server for AI agents, Node library.
Scales out: stateless API replicas, any number of workers on any number of servers, Redis/BullMQ queue, S3-compatible storage. Or a single process with a folder, on a Raspberry Pi.
Install
Docker (recommended)
docker run --rm -v "$PWD:/work" -w /work ghcr.io/cxmiloxx/tourwright render examples/slides.yaml --out videos/A full service (API + 2 workers + Redis):
cp .env.example .env # set TOURWRIGHT_API_TOKENS
docker compose up -d --build
docker compose up -d --scale worker=6From npm (quickest to try)
Node.js 22+, on Linux, macOS or Windows:
npm install -g tourwright
tourwright install # ffmpeg, Piper + voices, edge-tts, Chromium (no root)
tourwright install --plan # only show what it would use from this PC and what it would download
tourwright config set quality fullhd # your own defaults: quality, voice, fps… (tourwright config lists them)
tourwright record https://app.example.com --out tour.yaml # do the tour by hand: it writes the script
tourwright guide tour.yaml --open # the same tour as a step-by-step guide with screenshots (HTML, PDF, Markdown)
tourwright narrate tour.yaml --write # your AI (Claude, OpenAI, Ollama) rewrites the narration from the screens
tourwright check videos/*.yaml # which videos broke after a deploy, at which step, and the fix
tourwright fix tour.yaml --write # puts the new targets in the script
tourwright render tour.yaml --step 7 # film one step with its voice, without the whole video
tourwright install --pocket # + Pocket TTS: natural offline voices (about 1 GB)
tourwright clean # what each part takes on disk; removes downloads and leftovers
tourwright doctor # what works on this machineWithout installing anything globally: npx tourwright <command>. With pnpm: pnpm add -g tourwright
(on 2.0.0, add --no-optional).
The Redis queue and Claude for narrate are optional: install bullmq ioredis or @anthropic-ai/sdk next to
Tourwright when you use them (npm install -g bullmq ioredis). The Docker image already has them.
Without Docker (Linux, macOS, Windows)
Node.js 22+. tourwright install puts ffmpeg, Piper, voices, edge-tts and Chromium in TOURWRIGHT_HOME, with no
root or admin rights; what the system already has is kept.
git clone https://github.com/CXmiloxx/tourwright && cd tourwright
./scripts/install.sh # Linux / macOS (Windows: powershell -ExecutionPolicy Bypass -File scripts\install.ps1)
node bin/tourwright.js doctor # what works on this machine
npm link # optional: the `tourwright` commandEach piece is looked for on the PC first and only downloaded when it is missing:
Linux (x64, arm64) | macOS (Intel, Apple Silicon) | Windows 10/11 (x64, ARM) | |
Chromium | Chrome, Edge or Chromium (apt, dnf, pacman, Raspberry Pi OS), else downloaded | Chrome, Edge or Chromium, else downloaded | Chrome or Edge, else downloaded |
ffmpeg |
| Homebrew, MacPorts, Nix, else |
|
Piper (offline voices) |
|
|
|
Piper voices | Hugging Face cache, | same | same |
edge-tts (Microsoft voices) |
| same | same |
Python (for edge-tts, Pocket, Whisper) | the system's 3.10–3.13, else 3.12 is downloaded | same | same (not the Microsoft Store stub) |
Capture |
|
|
|
Also reused: a Chromium left by another Playwright or Puppeteer version, and CHROME_PATH, CHROME_BIN or
PUPPETEER_EXECUTABLE_PATH. Snap and Flatpak browsers are skipped (their sandbox blocks Playwright).
TOURWRIGHT_SYSTEM_BROWSER=0 always uses Playwright's own Chromium. tourwright doctor shows what was found.
Nothing is installed on the system: what is downloaded lives in one folder (TOURWRIGHT_HOME), and the Python
packages run in a virtual environment, so yours is never changed. To uninstall, delete that folder.
Xvfb (apt install xvfb, Linux only) gives the sharpest capture; without it Tourwright records headless
(screencast), which works everywhere Chromium runs. Clients of the HTTP API or MCP can be on any system.
Use it
From a site to a video, without writing selectors by hand:
tourwright explore https://app.example.com/login --draft app.yaml # asks for the login, writes the script
tourwright render app.yaml --dry-run # checks every step in seconds
tourwright render app.yaml --open # the video, in ./videos/app/The draft goes through every section of the site with narration taken from its pages; edit it in your words.
Credentials are asked for once, never shown and never written in the script (tourwright secret list;
tourwright forget deletes them).
tourwright init video.yaml # an example script
tourwright validate video.yaml
tourwright render video.yaml --dry-run # runs every step fast: tests selectors, no voice/video
tourwright render video.yaml --quality fullhd --voice salome --out out/
tourwright voices # voices available here
tourwright install-voice en_GB-alba-medium # any voice from huggingface.co/rhasspy/piper-voices
tourwright say "Hello there" --voice lessac --out hello.wavThe script format, every action and the voices: docs/SCRIPTS.md.
JSON Schema for editors and agents: schema/script.schema.json.
HTTP API
TOURWRIGHT_API_TOKENS=secret tourwright serve --worker --port 4700
curl -X POST localhost:4700/v1/jobs -H 'authorization: Bearer secret' -H 'content-type: application/json' \
-d '{"script": {"type": "slides", "slides": [{"title": "Hello", "say": "Hello from the API."}]}}'
curl localhost:4700/v1/jobs/<id> -H 'authorization: Bearer secret' # → status, result, download linksEndpoints, assets, webhooks: docs/API.md.
AI agents (MCP)
Claude Code, as a plugin (the MCP server plus a skill that writes, checks and renders the script):
/plugin marketplace add CXmiloxx/tourwright
/plugin install tourwright@tourwrightAny other MCP client (Claude Desktop, Cursor, VS Code…):
{ "mcpServers": { "tourwright": { "command": "tourwright", "args": ["mcp"] } } }Tools: tourwright_guide, tourwright_voices, tourwright_validate, tourwright_render, tourwright_job (and
tourwright_render_file with TOURWRIGHT_MCP_ALLOW_FILES=true). Point it at a remote API with TOURWRIGHT_API_URL
and TOURWRIGHT_API_TOKEN. Details: docs/AGENTS.md.
GitHub Action
Re-render your tours on every release, or fail the build when a deploy broke one:
- uses: CXmiloxx/tourwright@v2
with:
scripts: videos/*.yaml
command: check # or render: the videos become a workflow artifact
env:
TOURWRIGHT_SECRET_APP_PASSWORD: ${{ secrets.APP_PASSWORD }}Inputs: scripts, command, out, voice, quality, voices, version, upload (action.yml).
Node library
import { loadFile, render } from 'tourwright'
const result = await render(await loadFile('tour.yaml'), { out: 'videos/', quality: 'hd' })
console.log(result.paths.video, result.duration, result.chapters)Scaling
Size | Setup |
One machine |
|
One big machine |
|
Many machines | API replicas behind a load balancer, workers anywhere, same Redis + S3 bucket |
Kubernetes |
|
Each worker renders TOURWRIGHT_CONCURRENCY videos at a time (one Chromium + ffmpeg each: plan ~1–2 CPU and
~1 GB RAM per video at 720p). Workers run at low CPU and disk priority so a shared server stays responsive.
More: docs/DEPLOYMENT.md · configuration: docs/CONFIGURATION.md.
Security
API jobs run in a sandbox: data-only scripts (no JavaScript), files limited to the job's assets, optional host allowlist and private-network blocking, secrets off by default, per-token job isolation, signed download links. Read SECURITY.md before exposing the API to untrusted clients.
License
MIT. Piper voices have their own licenses (see each voice's model card); Edge voices are a Microsoft online service, check its terms for your use.
Available Tools
6 toolstourwright_checkCheck a script and propose fixesARead-onlyIdempotent
Run a script fast, without voice or video, against the real site. Returns every step that failed (the target it looked for, the page, the targets that page offers) and, when it can tell, the new target for it. For a YAML script given as text it also returns fixed: the same text with those targets replaced (comments kept). Use it after the site changed, then validate and render.
| Name | Required | Description | Default |
|---|---|---|---|
| vars | No | Values for the script variables ({{name}}): the same script makes a different video per set of values | |
| script | Yes | The script: an object, or YAML/JSON text. Read tourwright_guide first for the format. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly/openWorld/idempotent annotations, it explains what is returned for failures, that new targets are inferred when possible, and that YAML text input yields a `fixed` version preserving comments. This adds substantial behavioral context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded, dense, and free of filler. Each sentence adds purpose, return behavior, or usage guidance.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description does a good job explaining failure output and the `fixed` field. It does not fully specify the success case or complete response shape, but it is sufficient for a check tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds meaningful input-dependent behavior: when the script is provided as YAML text, the response includes a repaired `fixed` text field.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action: run a script quickly against the real site without voice or video, and return failed steps plus proposed target fixes. It clearly distinguishes this check behavior from render/validate follow-up actions.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a clear usage context: use after the site changed, then validate and render. It implies the alternative to full render by saying no voice or video, but does not explicitly state when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
tourwright_guideHow to write a Tourwright scriptARead-onlyIdempotent
The script format (browser walkthroughs and narrated slides), every action, voices and examples. Read it before writing a script.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint and closed-world behavior, so the agent knows this is a side-effect-free read. The description adds that the payload is documentation content (format, actions, voices, examples) but says nothing about size, structure, or whether it returns one document or sections — modest added value against the already-covered safety profile.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single sentence with the content summary front-loaded and the call-to-action at the end; nothing is redundant. The middle list ('every action, voices and examples') is slightly compressed and would read better as a clearer enumeration, but no filler is present.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no parameters, no output schema and no nested structures, the description carries most of the burden and does state what content comes back. It stops short of describing the document's shape or length, which would help an agent budget reading it, but nothing needed to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Zero parameters, so the baseline applies; there is no input semantics left for the description to carry. The one sentence is consistent with an argument-free fetch.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names the resource plainly: the Tourwright script format, covering browser walkthroughs, narrated slides, actions, voices and examples. An agent can tell this is a reference/guide fetch rather than an action tool, though it does not state a verb and overlaps thematically with the sibling tourwright_voices, leaving mild ambiguity about which one to open for voice details.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Read it before writing a script' gives an explicit precondition that selects this tool over the action siblings (validate, render, job). It does not name any exclusions or point to the follow-on siblings such as tourwright_validate for the step after reading, so guidance is clear but not complete.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
tourwright_jobJob statusBRead-onlyIdempotent
Status, progress and (when done) the result of a render job.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | The job id returned by tourwright_render with wait=false |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and openWorldHint=false, so the safety profile is covered. The description adds that the result appears only once done, which is useful, but says nothing about what status values exist, terminal states, or whether results expire.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with no wasted words. It is efficient, though the parenthetical carries meaning that could be stated more directly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description is the only source of return-shape information; it names the three returned aspects but not their form or the terminal conditions. For a polling tool this leaves the agent to infer how to decide when to stop.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the id parameter is already explained as coming from tourwright_render with wait=false. The description adds no further meaning about the identifier, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific resource (a render job) and the three things it returns: status, progress, and result. That is enough to tell it apart from tourwright_render, which starts a job, but the description never names that sibling explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The parenthetical '(when done)' implies this is a polling tool, yet the description never says to call it repeatedly until the job completes, nor points to tourwright_render with wait=true as the blocking alternative. The relevant context exists only in the schema's parameter text, not in the description itself.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
tourwright_renderRender a videoA
Queue a script for rendering. With wait=true (default) it waits until the video is ready and returns its links (and local paths), duration, chapters and captions; otherwise it returns the job id to poll with tourwright_job.
| Name | Required | Description | Default |
|---|---|---|---|
| vars | No | Values for the script variables ({{name}}): the same script makes a different video per set of values | |
| wait | No | Wait for the video (default true); false returns the job id at once, to poll with tourwright_job | |
| assets | No | Files the script refers to by name (images, music, uploads), base64-encoded | |
| script | Yes | The script: an object, or YAML/JSON text. Read tourwright_guide first for the format. | |
| options | No | Render settings that override the script | |
| waitSeconds | No | How long to wait for the video before returning the job as it is (default 900) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false, openWorldHint=true and idempotentHint=false, so the mutating/non-idempotent nature is covered. The description adds real value beyond that: it discloses the blocking semantics, the exact contents of a successful return (links, local paths, duration, chapters, captions), and the asynchronous escape hatch. It does not say whether repeated calls create duplicate jobs or whether rendering consumes credits, which would have earned a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two compact sentences with no filler, and the primary action is front-loaded ahead of the conditional behavior. The branching (wait=true vs otherwise) is expressed in a single parallel clause, which is easy for an agent to parse.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a six-parameter tool with a nested options object and no output schema, the description covers the two things an agent most needs: what the call returns and how to handle the async case. The schema itself points to tourwright_guide for the script format. Minor gaps remain around failure modes and job duplication, but nothing essential for a correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents every parameter, including wait, waitSeconds, vars, assets and options. The description only restates the wait behavior and the return payload, adding no syntax or format detail beyond the structured fields. Baseline 3 is appropriate when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence states a specific verb and resource: 'Queue a script for rendering.' The second sentence explains what the call produces and explicitly names tourwright_job as the polling sibling, so an agent can distinguish it from tourwright_validate, tourwright_check and tourwright_voices without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description clearly explains the default wait=true flow versus the fire-and-forget flow that returns a job id for tourwright_job, which is the key decision an agent must make. It stops short of stating when NOT to use the tool (for example, running tourwright_validate first) or which sibling to pick for related tasks, so it is clear context rather than full routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
tourwright_validateValidate a scriptARead-onlyIdempotent
Check a script without rendering it. Returns { ok } or the list of errors to fix.
| Name | Required | Description | Default |
|---|---|---|---|
| vars | No | Values for the script variables ({{name}}): the same script makes a different video per set of values | |
| script | Yes | The script: an object, or YAML/JSON text. Read tourwright_guide first for the format. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish readOnly, idempotent, and closed-world behavior, so the description only needs to add context. It does so usefully by disclosing the return shape ({ ok } or a list of errors), which is not covered by any output schema. It still doesn't say how deep validation goes or what kinds of errors are caught.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, front-loaded with the core action and followed by the return contract. No filler, though "the list of errors to fix" is slightly loose phrasing for a return value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a small two-parameter read-only tool with no output schema, the description covers what it does and what it returns, which is most of what an agent needs. The notable gap is the relationship to the adjacent tourwright_check and tourwright_guide tools, which is left unaddressed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, including the note that variables make a different video per value set and the instruction to read tourwright_guide first, so the schema carries parameter meaning. The description adds nothing about `script` or `vars` beyond what the schema already states.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
"Check a script without rendering it" gives a specific verb (check) and resource (script), and explicitly contrasts with rendering, which separates it from tourwright_render. However, it does not distinguish itself from the sibling tourwright_check, which an agent could plausibly confuse it with.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase "without rendering it" implies the intended pre-render validation step, but there is no explicit statement of when to pick this over tourwright_check or tourwright_guide, nor any mention of prerequisites. Usage is only implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
tourwright_voicesList voicesARead-onlyIdempotent
Text-to-speech voices available on the server and which engines work. Use a voice whose language matches the script.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and a closed-world scope, so the safety profile is covered structurally. The description adds that results include which engines work, hinting at the returned data, but it says nothing about how voices are identified or how the engine/voice relationship is expressed — information an agent needs to actually use the output.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, front-loaded with the resource being listed, with no filler. The phrasing 'and which engines work' is slightly compressed and could be clearer, but nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description needn't explain return shape in detail given the tool's simplicity, but it does flag the two things returned (voices and working engines) and adds the selection rule that motivates calling it. Nothing essential to invoking a zero-argument lister is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to disambiguate; the baseline for a parameterless tool applies. The absence of arguments is consistent with the description's framing of a plain enumeration call.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names the resource specifically (text-to-speech voices on the server) plus a secondary payload (engine compatibility), which is more than the title 'List voices' conveys. It is distinguishable from siblings like render, validate, and job, though it never explicitly states that it is the discovery/enumeration step.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The second sentence gives a downstream selection rule ('use a voice whose language matches the script'), which implies this is a lookup step to run before rendering. There is no explicit when-to-call guidance, no mention of alternatives, and no statement of prerequisites or that no arguments are needed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
2 tool updates
v2.2.0- Changed
tourwright_job1 field changed- added
Input schema / properties / id / descriptionAdded value: +"The job id returned by tourwright_render with wait=false"
- Changed
tourwright_render5 fields changed- added
Input schema / properties / options / descriptionAdded value: +"Render settings that override the script" - added
Input schema / properties / options / properties / quality / descriptionAdded value: +"Size of the video: sd 480p, hd 720p, fullhd 1080p, vertical 1080x1920, square 1080x1080" - added
Input schema / properties / options / properties / voice / descriptionAdded value: +"Voice for the whole video, overriding the script: a name from tourwright_voices" - added
Input schema / properties / wait / descriptionAdded value: +"Wait for the video (default true); false returns the job id at once, to poll with tourwright_job" - added
Input schema / properties / waitSeconds / descriptionAdded value: +"How long to wait for the video before returning the job as it is (default 900)"
6 tool updates
v0.1.0- First observed
tourwright_check - First observed
tourwright_guide - First observed
tourwright_job - First observed
tourwright_render - First observed
tourwright_validate - First observed
tourwright_voices
TDQS
Scored across 6 tools
Each tool maps to a distinct stage of the pipeline (voices, guide, validate, check, render, job), and descriptions clarify the validate-vs-check split (structure vs live-site targets). The only mild overlap is that validate and check both 'check a script', which a careless agent could conflate.
All tools share the tourwright_ prefix and a single lowercase word, which is predictable and readable. However, the words mix nouns (voices, job, guide) and verbs (validate, render, check), so it's not a uniform verb_noun scheme.
Six tools map cleanly onto a coherent authoring pipeline: reference (guide, voices), pre-flight (validate, check), execution (render), and status (job). Nothing feels redundant or missing at the count level.
The lifecycle from learning the format to validating, dry-running, rendering, and polling is fully covered. Minor gaps exist: no job listing/cancel operation and no cleanup or listing of previously rendered videos.
Maintenance
Related MCP Connectors
Narrated demo and tutorial videos of your web app, from a guide or your coding agent.
The AI video studio: records your web app, writes and voices the script, renders a tutorial MP4.
The AI video studio: records your web app, writes and voices the script, renders a tutorial MP4.
Make narrated, on-brand product videos of your real app from your coding agent or AI assistant.
Related MCP Servers
- AlicenseAqualityAmaintenanceYour coding agent makes the demo video — turns a storyboard.json into a narrated, captioned product-demo MP4; deterministic replay re-renders it in CI at ~$0.241,736 npm25MIT
- AlicenseNot gradedqualityAmaintenanceEnables AI agents to create polished product demo videos by controlling a real Chromium browser, recording actions, and rendering 1080p MP4s with narration, captions, and styled overlays.2MIT
- AlicenseNot gradedqualityBmaintenanceEnables agents to record narrated, zoom-animated product demo videos of websites entirely on-device, including outlining pages, scripting tours, recording MP4s, reviewing frames, and extracting embedded recipes to fork or rerender demos.15 npm4MIT
- AlicenseNot gradedqualityBmaintenanceEnables an AI agent to operate a web app, record a deterministic session, and compile an editable project into a polished MP4 with zooms, cuts, captions, callouts, and reproducible renders.MIT