synthesia-mcp
Click on "Deploy 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., "@synthesia-mcp Create a draft video of Anna saying 'Hello from Synthesia!'"
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.
synthesia-mcp
An MCP server that exposes the Synthesia avatar video API to MCP clients such as Claude Desktop. Local stdio transport, API-key auth via environment, draft-by-default rendering so iteration never burns enterprise video quota.
This is a Phase 1 MVP focused on a clean capability layer; opinionated educational-video workflows live in a separate Claude skill that builds on top of these tools.
Table of contents
Related MCP server: HeyGen MCP Server
What you can do with it
Once connected, you can ask Claude things like:
"List my Synthesia templates and show me the variables of the one called 'Lesson intro'."
"Create a draft 2-scene video introducing photosynthesis with the Anna avatar."
"Render that as a final video now."
"How's video
abc-123…doing? When it's done, make it public.""Upload
./diagram.pngto Synthesia and use it as the background of scene 2."
The server holds the API key; Claude never sees it.
Requirements
Node.js ≥ 20 (the server is shipped as an ESM bundle and uses the built-in
fetch).A Synthesia API key. Enterprise plan recommended — the API is enterprise-tier on most plans. Find or create a key in Synthesia account settings: https://app.synthesia.io/#/account.
An MCP-capable client. Claude Desktop is the primary target; the server works with any client that supports stdio MCP servers (e.g. Cursor, MCP Inspector).
Install & connect to Claude Desktop
1. Get the server onto your machine
Clone or unzip this repository, then:
cd synthesia-mcp
npm install
npm run buildThat produces dist/index.js — the executable the MCP client will run.
2. Register the server with Claude Desktop
Open your Claude Desktop config:
macOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:
%APPDATA%\Claude\claude_desktop_config.jsonLinux:
~/.config/Claude/claude_desktop_config.json
Add (or merge) an entry under mcpServers:
{
"mcpServers": {
"synthesia": {
"command": "node",
"args": ["/ABSOLUTE/PATH/TO/synthesia-mcp/dist/index.js"],
"env": {
"SYNTHESIA_API_KEY": "your-synthesia-api-key-here"
}
}
}
}Use the absolute path to dist/index.js (Claude Desktop does not resolve ~ or relative paths).
3. Restart Claude Desktop
Quit fully and reopen. The Synthesia tools should appear in the tool picker. If they don't, check ~/Library/Logs/Claude/mcp*.log (macOS) or the equivalent on your OS — the server logs to stderr and Claude Desktop captures it.
First run
Once connected, ask Claude:
List my Synthesia templates.
If you see your templates: you're set. If you see an auth_error: the API key is wrong or missing — double-check it in claude_desktop_config.json (no quotes inside the value, no trailing spaces) and restart Claude Desktop.
Render your first video — for free:
Create a draft 1-scene video titled "Hello" with the Anna avatar on a white_studio background. The avatar should say "Hello from Synthesia! This is my first API video."
Claude will call create_video with render_mode: "draft" by default. The result includes a videoId and a note that this is a watermarked test render. Renders take a few minutes; ask Claude to check on it:
Is that video ready yet?
Claude will call get_video and either tell you to wait, or hand you the download URL.
Only when you're happy with the draft, ask explicitly:
Render that as a final video.
A final render counts against your account's video quota.
Configuration
Required: SYNTHESIA_API_KEY
Passed as an environment variable in claude_desktop_config.json's env block. Per the MCP authorization specification, stdio servers retrieve credentials from the environment rather than implementing OAuth; that's exactly what this server does.
Optional: ~/.synthesia-mcp/config.json
Holds non-secret settings, primarily your custom avatar and voice IDs (Synthesia has no API endpoint for avatar/voice discovery, so any custom or personal avatar must be registered here to be discoverable via list_avatars).
Shape (see config.example.json):
{
"customAvatars": [
{ "id": "uuid-from-studio", "name": "My Personal Avatar", "notes": "..." }
],
"customVoices": [
{ "id": "uuid-from-studio", "name": "My Custom Voice", "language": "English (UK)" }
],
"defaults": {
"aspectRatio": "16:9"
}
}To get a custom avatar ID: open https://app.synthesia.io/#/actors, hover the avatar, open the three-dot menu, and pick Copy ID.
Override the config path with SYNTHESIA_MCP_CONFIG=/path/to/config.json if you want it somewhere else.
Refreshing the stock avatar/voice catalogs
The repo ships with a small seed catalog for offline use. To get the full lists from the live Synthesia documentation:
npm run refresh-catalogThat rewrites catalog/avatars.json and catalog/voices.json. Commit them. Re-run whenever Synthesia publishes new avatars or voices.
Tool reference
All tools return a JSON object inside an MCP text content block. Errors carry isError: true with a structured { code, message, remediation, details? } envelope.
Discovery
Tool | What it does |
| Lists stock avatars (bundled catalog snapshot) + custom avatars from config. Filter by |
| Lists stock voices (snapshot) + custom voices from config. Filter by |
| Lists STUDIO templates with their variable names. Paginated ( |
| Returns a single template's full variable list — call this before |
Creation
Tool | What it does |
| Creates a multi-scene video from raw scene objects ( |
| Renders a STUDIO template by passing |
Both creation tools return a videoId immediately — Synthesia renders asynchronously, often in minutes. Check progress with get_video.
Lifecycle
Tool | What it does |
| Returns status ( |
| Lists videos in the account. Paginated, filterable by |
| Updates |
| PERMANENT. Double-gated: refuses unless |
Assets
Tool | What it does |
| Uploads an image/video and returns an |
| Uploads narration audio (mp3 / |
Tip: scene background fields and template media variables accept URLs directly. upload_asset is only needed when the media isn't publicly reachable or a stable asset ID is preferred.
Design notes
A few decisions worth knowing about as a user:
Draft-by-default. Every render path defaults to
render_mode: "draft"(Synthesiatest: true) — free, watermarked, no quota.finalmust be requested explicitly.Server-side validation. Mismatched template variable names, malformed script tags, and disallowed asset content types are caught locally before a request reaches Synthesia, so failures arrive instantly with the exact fix instead of after a wasted render.
Traceability. Every created video gets a
callbackId(auto-stampedmcp/yyyy-mm-dd/title-slugif you don't supply one). Useful for spotting MCP-originated videos in a shared workspace and for the planned Phase 4 webhook integration.Token-frugal responses. Tools return curated fields, not raw API payloads, to keep your context window healthy across long workflows.
Logging stays out of the way. All logs go to stderr (stdout is reserved for the MCP protocol). The API key is registered with a redactor so it can never accidentally appear in a log line.
Rate-limit aware. On HTTP 429, the server reads
RateLimit-Resetand retries once after the indicated wait (capped). Synthesia Enterprise's tier limits are generous enough that you'll rarely see this.No waiting/polling tool by design. Renders can take minutes; blocking a chat turn that long is worse than a quick check-in. Use
get_videowhen you're curious.Hosted-readiness without speculation. The credential layer is isolated behind a
CredentialProviderinterface; the tool registration is transport-agnostic. Switching to a hosted Streamable HTTP deployment with OAuth 2.1 later is a contained swap, not a rewrite.
Developer guide
Layout
src/
index.ts # entry: wires credentials → client → tools → stdio transport
credentials.ts # CredentialProvider interface + EnvCredentialProvider
config.ts # local config loading (custom avatars/voices, defaults)
catalog-loader.ts # reads catalog/*.json
logger.ts # stderr-only logger with secret redaction
errors.ts # SynthesiaMcpError + error code enum
synthesia/
client.ts # HTTP client: auth, two hosts, 429 retry, error mapping
types.ts # minimal API response types
util/
escape.ts # templateData text entity escaping
script-tags.ts # break/sub tag validator
tooling.ts # ok/fail envelopes, guard wrapper, callbackId stamping
tools/
discovery.ts # list_avatars, list_voices
templates.ts # list_templates, get_template
videos.ts # create_video, create_video_from_template, get_video, list_videos, update_video, delete_video
assets.ts # upload_asset, upload_script_audio
catalog/
avatars.json # seed snapshot; regenerate with npm run refresh-catalog
voices.json # seed snapshot
scripts/
refresh-catalog.mjs # regenerates the catalog files from docs.synthesia.io
test/
smoke.mjs # offline smoke test (no API key required)Build & test
npm install
npm run build # tsc → dist/
npm run smoke # offline: spawns the built server, calls list_avatarsThe smoke test verifies all 12 tools are registered and that list_avatars returns catalog data — without making network calls, so no API key is required.
Adding a new tool
Create or edit a module in
src/tools/.Define a zod schema for the inputs (it's both the validator and the source of the JSON Schema advertised to clients).
Wrap the handler with
guard(name, handler)fromutil/tooling.tsto get consistent error envelopes.Return data via
ok({...})— keep the payload curated, not the raw API response.Register the module from
src/index.ts.Add the tool name to
EXPECTED_TOOLSintest/smoke.mjs.
Authorization architecture
The MCP authorization specification draws a clean line between transports:
stdio (local): retrieve credentials from the environment, no OAuth flow.
Streamable HTTP (remote): OAuth 2.1 with PKCE, dynamic client registration, etc.
This server ships only the stdio path. The CredentialProvider interface in credentials.ts is the seam: a future hosted variant adds an HTTP transport in index.ts and a session-scoped provider implementing the same interface — no tool code changes. The Synthesia client always reads the key through the interface, never directly from process.env.
Error model
All failures surface as SynthesiaMcpError instances. The guard() wrapper turns them into MCP tool results with isError: true and the structured { error: { code, message, remediation, details? } } envelope. Error codes are deliberately few and category-level:
auth_error— 401/403 from Synthesiaconfig_error— missing env var or malformed config filevalidation_error— local pre-flight failed; nothing was sent to Synthesianot_found— 404 from Synthesiarate_limited— 429 after retrymoderation_rejected— Synthesia content moderationfile_error— local file unreadable, download failed, wrong typeupstream_error— everything else from the Synthesia side
remediation is written for the LLM to self-correct in the next turn — concrete, specific, with the exact field name or available values where possible.
Catalog refresh
npm run refresh-catalog fetches https://docs.synthesia.io/reference/avatars.md and …/voices.md, parses the markdown tables, and overwrites the JSON catalogs. The refresh script is intentionally simple: no schema migrations, no diffs — just replace and commit.
Roadmap
This server is the MCP layer of a two-layer plan. Things deliberately not in v1:
Phase 4: webhook tools (Synthesia fires
video.completed/video.failedwith captions, thumbnails, and yourcallbackIdin the payload). Requires a public HTTP receiver; polling viaget_videosuffices for interactive authoring.Phase 5: translations, XLIFF export/import, dubbing — the localization surface is substantial and earns its own milestone.
Phase 6: hosted Streamable HTTP deployment with OAuth 2.1, multi-account profiles, evals.
On top of this server, a separate Claude skill handles the educational workflow: eliciting audience, learning objectives, target duration (translated into a word-count budget), tone, and pedagogical structure; co-writing the script scene by scene; then delegating execution to these tools. The skill is opinionated and customizable per user; this server stays plug-and-play.
License
MIT.
Available Tools
12 toolscreate_videoCreate a video (from scenes)A
Create a Synthesia avatar video from one or more scenes (avatar + background + script each). Rendering is asynchronous: this returns a videoId immediately; check progress later with get_video. DEFAULTS TO A FREE DRAFT (watermarked test render); pass render_mode='final' only when the user explicitly wants to spend quota on a final render. For visually rich layouts (on-screen text, images), prefer create_video_from_template with a STUDIO-designed template.
Inputs: title (required), scenes (required), description, aspectRatio, +6 more.
create_video_from_templateCreate a video from a templateA
Create a Synthesia video from a STUDIO template by substituting its variables (templateData). The server fetches the template first and validates every templateData key against its declared variables — variable names are case-sensitive. Text values are HTML-entity-escaped automatically (Synthesia requirement); media variables accept an uploaded asset ID or a URL. DEFAULTS TO A FREE DRAFT (watermarked); pass render_mode='final' only on explicit approval. Returns a videoId immediately; check progress with get_video.
Inputs: templateId (required), templateData (required), title, description, +7 more.
delete_videoDelete a videoADestructive
PERMANENTLY delete a video from the Synthesia account. Destructive and double-gated: the call is refused unless confirm=true is passed. Only set confirm=true after the user has explicitly confirmed deletion of this specific video.
Inputs: videoId (required), confirm.
get_templateGet template detailsARead-only
Retrieve a single Synthesia template by ID, including its full variable list. Call this before create_video_from_template to see exactly which templateData keys are expected (variable names are case-sensitive).
Inputs: templateId (required).
get_videoGet video status / download linkARead-only
Retrieve a Synthesia video by ID: render status (in_progress / complete / error / rejected), and once complete, a time-limited download URL, duration, and thumbnail. Use this to check on videos created with create_video or create_video_from_template. Renders take minutes — do not call this in a tight loop.
Inputs: videoId (required).
list_avatarsList avatarsARead-only
List Synthesia avatars available for video creation: stock avatars from a bundled catalog snapshot, plus any custom/personal avatars registered in the local server config. Returns avatar IDs to use as the avatar field in create_video. Note: Synthesia has no API endpoint for avatar discovery, so the stock list is a snapshot and may be incomplete; custom avatar IDs must be registered in the config file (copied from STUDIO via the avatar's three-dot menu → Copy ID).
Inputs: query, gender, version, source.
list_templatesList templatesARead-only
List Synthesia video templates (created in STUDIO) with their IDs and variable names. Templates are the way to produce rich, designed videos via the API — use create_video_from_template with a templateId from this list. Paginated: pass the returned nextOffset as offset to fetch more.
Inputs: limit, offset, source.
list_videosList videosARead-only
List videos in the Synthesia account (created via API or STUDIO), newest context first. Paginated: pass the returned nextOffset as offset to fetch more.
Inputs: limit, offset, source.
list_voicesList voicesARead-only
List Synthesia text-to-speech voices: stock voices from a bundled catalog snapshot plus custom voices registered in the local server config. Returns voice IDs for the avatarSettings.voice field in create_video. IMPORTANT: voices are optional — if omitted, Synthesia automatically uses its recommended voice for the chosen avatar, which is a good default. The stock list is a snapshot and may be incomplete.
Inputs: query, language, gender.
update_videoUpdate video metadataB
Update a video's title, description, visibility, or call-to-action button. The main use is flipping visibility to 'public' to activate the Synthesia share page for a finished video.
Inputs: videoId (required), title, description, visibility, +1 more.
upload_assetUpload an image/video assetA
Upload an image or video to Synthesia and get back an asset ID, usable as a scene background in create_video or as a media variable value in create_video_from_template. Accepted types: image/jpeg, image/png, image/svg+xml, video/mp4, video/webm (GIF and WebP are rejected by Synthesia). Provide a local filePath or a url. TIP: backgrounds and media variables also accept URLs directly — uploading is only needed for non-public files or when a stable asset ID is preferred. For media variables, match the aspect ratio of the element being replaced to avoid stretching.
Inputs: filePath, url, contentType.
upload_script_audioUpload script audio (mp3 narration)A
Upload pre-recorded narration audio (mp3 / audio/mpeg only) to use INSTEAD of text-to-speech: pass the returned ID as scriptAudioId (with scriptLanguage) in a create_video scene. NOTE: Synthesia processes uploaded script audio asynchronously — if video creation fails right after uploading with an error about the asset, wait a moment and retry; processing must complete before the audio is usable.
Inputs: filePath, url.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 12 tools
Each tool targets a distinct resource or action: two creation methods for different use cases, dedicated listing tools for each entity type, and specific operations for deletion, updating, and uploading. No two tools have overlapping purposes; descriptions clearly differentiate them.
All tool names follow a consistent verb_noun pattern using lowercase with underscores (e.g., create_video, list_templates, upload_asset). Only create_video_from_template uses a slight variant ('from_template'), but it remains within the pattern and is clear.
With 12 tools, the set is well-scoped for a video creation service. It covers creation, retrieval, listing, updating, deletion, and asset uploads without being excessive or sparse.
The tool surface covers the core video lifecycle: create (two ways), read status, list, update metadata, delete, plus supporting operations for templates, avatars, voices, and asset/audio uploads. Missing features (e.g., custom avatar management) are intentionally handled via configuration, not gaps.
Related MCP Connectors
Build real-time AI avatar personas and videos; manage voices, knowledge, sessions and meetings.
Create AI talking-avatar marketing videos from a script or product idea.
Create and edit videos, images, voiceovers, music, and avatars with the VideoGen API.
Create and manage cinematic AI video renders through the Future Video Studio Agent API.
Related MCP Servers
AlicenseNot gradedqualityNot gradedmaintenanceEnables Claude Desktop and Agents to generate AI avatars and videos through the HeyGen API, providing tools to create and manage avatar videos with specified text and voice options.191 PyPI44MIT- AlicenseAqualityCmaintenanceEnables AI assistants to generate AI avatar videos, manage templates, and work with assets through natural language commands via the HeyGen API.7MIT
- AlicenseNot gradedqualityCmaintenanceExposes video generation and editing tools to MCP-capable clients, enabling text-to-video, image-to-video, video editing, reusable voice and character profiles, and task status queries through natural language.4MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to create and manage video projects, write story and brief, convert, estimate costs, propose paid actions, run approved proposals, discard and restore assets.3MIT