Animation Machine MCP server docs
For AI agents: https://animation-machine.com/docs/mcp.md (same content, plain Markdown)
A hosted (remote) Model Context Protocol server that lets AI agents render HTML animations to MP4/GIF and finish videos with music, voiceover and captions.
- Server URL:
https://animation-machine.com/mcp - Transport: Streamable HTTP (stateless; every JSON-RPC request gets one JSON response)
- Protocol versions:
2025-11-25,2025-06-18,2025-03-26,2024-11-05 - Authentication: OAuth 2.1 (PKCE S256; dynamic client registration or client ID metadata documents) or a personal API key as
Authorization: Bearer am_live_… - Pricing: included in the Animation Machine subscription ($5/month), which is required to use the server
- Human-friendly overview: https://animation-machine.com/mcp-server · This document as Markdown: https://animation-machine.com/docs/mcp.md
What it does
AI assistants write animation code well (GSAP, CSS keyframes, the Web Animations API, Lottie, Three.js, canvas, p5.js, SVG) but cannot play it back and record it. This server does that last mile:
- The agent writes a self-contained HTML animation, or picks a template.
preview_framereturns one still frame so the agent can check its work.renderplays the page frame by frame in a real browser and encodes MP4 or GIF, in up to three aspect ratios, adding music, voiceover, captions, title/end cards and a logo if asked.- The agent polls
get_joband hands the user a download link, a shareable watch page and a link to keep editing in Animation Machine Studio.
It renders code exactly. It is not a generative text-to-video model.
Connect
claude.ai, Claude Desktop, Claude mobile
Settings → Connectors → Add custom connector → URL https://animation-machine.com/mcp → Connect → sign in → Allow.
Claude Code
claude mcp add --transport http animation-machine https://animation-machine.com/mcp
Then run /mcp → Authenticate. With an API key instead:
claude mcp add --transport http animation-machine https://animation-machine.com/mcp --header "Authorization: Bearer am_live_…"
ChatGPT
Settings → Apps & Connectors → Advanced → enable Developer mode → Create → URL https://animation-machine.com/mcp, authentication OAuth → sign in → Allow.
Cursor (~/.cursor/mcp.json)
{ "mcpServers": { "animation-machine": { "url": "https://animation-machine.com/mcp", "headers": { "Authorization": "Bearer am_live_…" } } } }
VS Code (.vscode/mcp.json)
{ "servers": { "animation-machine": { "type": "http", "url": "https://animation-machine.com/mcp", "headers": { "Authorization": "Bearer am_live_…" } } } }
stdio-only clients
npx mcp-remote https://animation-machine.com/mcp --header "Authorization: Bearer am_live_…"
Authentication
API keys. Sign in at https://animation-machine.com/app.html → account menu → AI agents (MCP) → Create API key. A key is shown once and can be revoked from the same panel. Send it as Authorization: Bearer am_live_….
OAuth. An unauthenticated request returns 401 with WWW-Authenticate: Bearer resource_metadata="https://animation-machine.com/.well-known/oauth-protected-resource", scope="render".
| Endpoint | URL |
|---|---|
| Protected resource metadata | https://animation-machine.com/.well-known/oauth-protected-resource |
| Authorization server metadata | https://animation-machine.com/.well-known/oauth-authorization-server |
| Authorization | https://animation-machine.com/oauth/authorize |
| Token | https://animation-machine.com/oauth/token (form-urlencoded or JSON) |
| Dynamic client registration | https://animation-machine.com/oauth/register |
| Revocation | https://animation-machine.com/oauth/revoke |
Public clients only (token_endpoint_auth_method: none), PKCE S256 required, scope render, resource https://animation-machine.com/mcp. Client ID metadata documents are supported (client_id = an https URL). Loopback redirect URIs (http://localhost, 127.0.0.1, [::1]) match on any port. Access tokens last 7 days; refresh tokens rotate on every use. The user sees a consent screen naming your app, and needs an active subscription to allow it.
What a connection can do: render, read the user's own renders and jobs, search music and write Post Kits. It cannot see billing, change the account or touch other users' data.
Typical workflow
get_account (optional: plan, limits, job in progress)
preview_frame { html, at_seconds } → image + animation_length_seconds
render { html, aspects, music_url, … } → { job_ids }
get_job { job_id } … every retry_after_sec … → status "done" + download_url
post_kit { job_id } (optional: social copy)
Renders usually finish in 1–3 minutes. Jobs are asynchronous: render returns immediately and you poll get_job, respecting its retry_after_sec.
Writing animations that render well
- Make the page self-contained: inline CSS/JS; libraries from a CDN and fonts from Google Fonts are fine. Multi-file projects can be sent as
filesor an uploaded zip. - Let the length be detectable: a GSAP timeline, CSS animations or Web Animations are measured automatically. For canvas or custom loops, declare
const TOTAL = <seconds>;in a script, or passduration_seconds. - Size with viewport units (
vw,vh,vmin) so one animation works at 16:9, 9:16 and 1:1. - Pages render in a sandboxed browser with public internet access only (no private networks).
Tools
get_account: Account and limits
Your Animation Machine plan, renders used this month, any job in progress, and the limits that apply to agents. Call this first if unsure.
Behaviour: read-only.
No parameters.
render: Render an animation or finish a video
Turn an HTML animation (GSAP, CSS, Web Animations, Lottie, Three.js, canvas, Claude Design exports…) into an MP4 or GIF, or finish an existing video (add music, voiceover, captions, title cards, logo). Pass ONE source: html, files, or upload_id. Returns job_ids immediately; poll get_job until status is "done" to get the download link. One job at a time per account; if you get "busy", wait retry_after_sec and try again. Tip: call preview_frame first to check the animation looks right.
Behaviour: creates data.
| Parameter | Type | Required | Description |
|---|---|---|---|
html | string | A complete, self-contained HTML page with the animation (inline CSS/JS; CDN <script>/<link> tags are fine). Max 2 MB. | |
files | object | A multi-file project: {"index.html": "...", "style.css": "...", "img/logo.png": {"base64": "..."}}. Max 5 MB total. | |
upload_id | string | A .zip / .html / video file uploaded with create_upload. | |
aspects | array of "16:9"/"9:16"/"1:1" | Output shapes. One file per aspect, rendered back-to-back. Default ["16:9"]. Use ["16:9","9:16","1:1"] for YouTube + TikTok/Reels + feed. (≤ 3 items) | |
resolution | "1080p" | "720p" | Default 1080p. 720p (16:9 only) renders faster. | |
format | "mp4" | "gif" | Default mp4. GIFs are capped at 15 seconds. | |
fps | 24 | 30 | Default 30. | |
duration_seconds | number | Force the length. Only needed if the animation has no detectable length (no GSAP timeline, CSS/Web animation, Lottie or const TOTAL = <seconds>). (min 1, max 60) | |
loop_count | integer | Repeat the animation N times. Default 1. (min 1, max 3) | |
crop_to_fill | boolean | Crop a 16:9 design to fill 9:16 or 1:1 instead of letterboxing. | |
music_url | string | Background music: a track "url" from search_music. | |
music_volume | number | Music volume 0–1. Default 0.15 (bed under voice). Use ~0.6 when there is no voiceover. (min 0, max 1) | |
music_fade | boolean | Fade the music in and out. Default true. | |
voiceover_text | string | Narration script, spoken by an AI voice and mixed in. Max 5 per day via agents. (≤ 1500 chars) | |
voiceover_voice | string | Voice id from list_voices. Default "Kore". | |
voiceover_speed | number | Default 1.0. (min 0.5, max 2) | |
captions | boolean | Burn in auto-captions of the speech (voiceover or the video's own audio). | |
caption_style | "subtle" | "bold" | "cinematic" | "block" | "neon" | "yellow" | "karaoke" | Default "subtle". | |
caption_position | "bottom" | "top" | ||
caption_language | "es" | "pt" | "fr" | "de" | "it" | "hi" | "ja" | "ko" | "zh" | "ar" | "ru" | "id" | "tr" | "nl" | "pl" | "vi" | Translate captions into this language. | |
text_overlay | string | A small corner stamp like "@yourhandle". (≤ 60 chars) | |
intro_title | string | Add a 3-second title card before the animation. (≤ 80 chars) | |
intro_subtitle | string | (≤ 120 chars) | |
outro_title | string | Add a 3-second end card, e.g. "Try it free at example.com". (≤ 80 chars) | |
outro_subtitle | string | (≤ 120 chars) | |
logo_upload_id | string | A PNG/JPG logo uploaded with create_upload; placed bottom-right. |
Returns (structuredContent): job_ids, jobs, status, retry_after_sec, error, busy.
render_template: Render a ready-made template
Render a polished motion-graphics template from a few fields — no HTML needed. Templates: "title_card": Big title with an optional subtitle and accent line. Good for intros, chapter cards, announcements. Fields: title (required, ≤60 chars), subtitle (optional, ≤100 chars), accent_color (hex, default #7c5cff), background (hex, default #0b0b14), duration (seconds 2–15, default 5). "lower_third": Name + role bar that slides in at the lower left, like a TV interview caption. Good for speaker intros. Fields: name (required, ≤40 chars), role (optional, ≤60 chars), accent_color (hex, default #00c2a8), background (hex, default #101820), duration (seconds 2–15, default 5). "quote": A quote revealed line by line with the author underneath. Good for testimonials and social posts. Fields: quote (required, ≤220 chars), author (optional, ≤60 chars), accent_color (hex, default #ffb020), background (hex, default #14110f), duration (seconds 2–15, default 7). "stat": A big number that counts up, with a label. Good for milestones, metrics, results ("10,000 users"). Fields: value (required number, e.g. 10000), prefix (optional, e.g. $), suffix (optional, e.g. % or +), label (optional, ≤80 chars), accent_color (hex, default #3fd17a), background (hex, default #0c1410), duration (seconds 2–15, default 5). Accepts the same output options as render (aspects, music_url, voiceover_text…). Returns job_ids; poll get_job.
Behaviour: creates data.
| Parameter | Type | Required | Description |
|---|---|---|---|
template | "title_card" | "lower_third" | "quote" | "stat" | yes | |
fields | object | yes | Template fields (which ones apply depends on the template, see the description). |
fields.title | string | title_card: the headline | |
fields.subtitle | string | title_card: optional second line | |
fields.name | string | lower_third: person or brand name | |
fields.role | string | lower_third: optional role/title | |
fields.quote | string | quote: the quote text | |
fields.author | string | quote: optional attribution | |
fields.value | number | stat: the number to count up to | |
fields.prefix | string | stat: e.g. "$" | |
fields.suffix | string | stat: e.g. "%" or "+" | |
fields.label | string | stat: text under the number | |
fields.accent_color | string | Hex color, e.g. "#7c5cff" | |
fields.background | string | Hex color | |
fields.duration | number | Seconds | |
aspects | array of "16:9"/"9:16"/"1:1" | Output shapes. One file per aspect, rendered back-to-back. Default ["16:9"]. Use ["16:9","9:16","1:1"] for YouTube + TikTok/Reels + feed. (≤ 3 items) | |
resolution | "1080p" | "720p" | Default 1080p. 720p (16:9 only) renders faster. | |
format | "mp4" | "gif" | Default mp4. GIFs are capped at 15 seconds. | |
fps | 24 | 30 | Default 30. | |
loop_count | integer | Repeat the animation N times. Default 1. (min 1, max 3) | |
crop_to_fill | boolean | Crop a 16:9 design to fill 9:16 or 1:1 instead of letterboxing. | |
music_url | string | Background music: a track "url" from search_music. | |
music_volume | number | Music volume 0–1. Default 0.15 (bed under voice). Use ~0.6 when there is no voiceover. (min 0, max 1) | |
music_fade | boolean | Fade the music in and out. Default true. | |
voiceover_text | string | Narration script, spoken by an AI voice and mixed in. Max 5 per day via agents. (≤ 1500 chars) | |
voiceover_voice | string | Voice id from list_voices. Default "Kore". | |
voiceover_speed | number | Default 1.0. (min 0.5, max 2) | |
captions | boolean | Burn in auto-captions of the speech (voiceover or the video's own audio). | |
caption_style | "subtle" | "bold" | "cinematic" | "block" | "neon" | "yellow" | "karaoke" | Default "subtle". | |
caption_position | "bottom" | "top" | ||
caption_language | "es" | "pt" | "fr" | "de" | "it" | "hi" | "ja" | "ko" | "zh" | "ar" | "ru" | "id" | "tr" | "nl" | "pl" | "vi" | Translate captions into this language. | |
text_overlay | string | A small corner stamp like "@yourhandle". (≤ 60 chars) | |
intro_title | string | Add a 3-second title card before the animation. (≤ 80 chars) | |
intro_subtitle | string | (≤ 120 chars) | |
outro_title | string | Add a 3-second end card, e.g. "Try it free at example.com". (≤ 80 chars) | |
outro_subtitle | string | (≤ 120 chars) | |
logo_upload_id | string | A PNG/JPG logo uploaded with create_upload; placed bottom-right. |
Returns (structuredContent): job_ids, jobs, status, retry_after_sec, error, busy.
preview_frame: Preview one frame
Render a single still frame of an HTML animation at a given time and return it as an image, plus the detected animation length. Use it to check layout, fonts and timing before a full render. Takes ~10–30s. Counts as your one job while it runs.
Behaviour: read-only.
| Parameter | Type | Required | Description |
|---|---|---|---|
html | string | A complete, self-contained HTML page with the animation (inline CSS/JS; CDN <script>/<link> tags are fine). Max 2 MB. | |
files | object | A multi-file project: {"index.html": "...", "style.css": "...", "img/logo.png": {"base64": "..."}}. Max 5 MB total. | |
upload_id | string | A .zip / .html / video file uploaded with create_upload. | |
at_seconds | number | Time of the frame. Default 0. Try the middle or end of the animation. (min 0) | |
aspect | "16:9" | "9:16" | "1:1" | Default 16:9. | |
duration_seconds | number | Force the length if it cannot be detected. (min 1, max 60) |
get_job: Check a job
Status of a render or preview: queued / rendering (with progress_pct) / done / error. When done, returns download_url (works without login for 24h), watch_url (a shareable page) and studio_url (open in the Animation Machine editor). Respect retry_after_sec between polls.
Behaviour: read-only.
| Parameter | Type | Required | Description |
|---|---|---|---|
job_id | string | yes |
Returns (structuredContent): job_id, status, progress_pct, queue_position, retry_after_sec, download_url, watch_url, studio_url, duration_seconds, format, error.
cancel_job: Cancel a job
Cancel a queued or running render (and any later versions in the same batch).
Behaviour: destructive.
| Parameter | Type | Required | Description |
|---|---|---|---|
job_id | string | yes |
create_upload: Get an upload link
For files you have on disk: a .zip animation project, an .html file, a video to finish (.mp4/.mov/.m4v/.webm, ≤95 MB, ≤3 min) or a logo (.png/.jpg). Returns an upload_url — PUT the raw file bytes to it (e.g. curl -T file.mp4 "<upload_url>"), then pass upload_id to render. Links expire in 1 hour. Not needed for HTML you generated: pass it inline as "html".
Behaviour: creates data.
| Parameter | Type | Required | Description |
|---|---|---|---|
filename | string | yes | e.g. "promo.mp4" |
Returns (structuredContent): upload_id, upload_url, method, max_mb, expires_in_sec, error.
search_music: Find background music
Search royalty-free (CC0) music by mood or genre, e.g. "upbeat corporate", "lofi chill", "cinematic trailer". Pass a result's url as music_url to render.
Behaviour: read-only.
| Parameter | Type | Required | Description |
|---|---|---|---|
query | string | yes |
list_voices: List voiceover voices
Voices for voiceover_text in render. Premium voices sound most natural; standard voices are always available.
Behaviour: read-only.
No parameters.
post_kit: Write social post copy
AI looks at a finished render and writes ready-to-paste social copy: caption, 3 hook lines, hashtags and a longer description. Optional context = topic or script. Max 20 per day.
Behaviour: read-only.
| Parameter | Type | Required | Description |
|---|---|---|---|
job_id | string | yes | |
context | string | (≤ 600 chars) |
list_renders: Recent renders
Your 10 most recent renders (from the web app or agents), newest first, with job_ids you can pass to get_job or post_kit.
Behaviour: read-only.
No parameters.
Templates (render_template)
| Template | What it is | Fields |
|---|---|---|
title_card | Big title with an optional subtitle and accent line. Good for intros, chapter cards, announcements. | title (required, ≤60 chars), subtitle (optional, ≤100 chars), accent_color (hex, default #7c5cff), background (hex, default #0b0b14), duration (seconds 2–15, default 5) |
lower_third | Name + role bar that slides in at the lower left, like a TV interview caption. Good for speaker intros. | name (required, ≤40 chars), role (optional, ≤60 chars), accent_color (hex, default #00c2a8), background (hex, default #101820), duration (seconds 2–15, default 5) |
quote | A quote revealed line by line with the author underneath. Good for testimonials and social posts. | quote (required, ≤220 chars), author (optional, ≤60 chars), accent_color (hex, default #ffb020), background (hex, default #14110f), duration (seconds 2–15, default 7) |
stat | A big number that counts up, with a label. Good for milestones, metrics, results ("10,000 users"). | value (required number, e.g. 10000), prefix (optional, e.g. $), suffix (optional, e.g. % or +), label (optional, ≤80 chars), accent_color (hex, default #3fd17a), background (hex, default #0c1410), duration (seconds 2–15, default 5) |
Job statuses
| Status | Meaning |
|---|---|
queued | Waiting for the render server (queue_position given) |
rendering | In progress (progress_pct given) |
scheduled | A later aspect ratio of a multi-aspect request, waiting for the previous one |
done | Finished: download_url (signed, works without login for 24 h), watch_url (shareable page), studio_url (open in the editor; the user must be signed in) |
error | Failed: error explains why; error_code may be DURATION_UNKNOWN (pass duration_seconds) or TOO_LONG |
cancelled / failed | Cancelled, or skipped because an earlier version in the batch failed |
Limits
The render server works one job at a time and people using the website go first, so:
- One job at a time per account (a render request, including all its aspect ratios, or a preview). A second call returns
busy: trueandretry_after_sec. - If the agent queue is full, calls return
busy: truewithretry_after_sec. Wait and retry; don't loop rapidly. - HTML animations up to 60 s, GIFs up to 15 s, videos you finish up to 3 min. Loops count toward these.
- Up to 1080p, 24 or 30 fps, up to 3 aspect ratios per request.
- Inline HTML ≤ 2 MB;
files≤ 5 MB / 60 files; uploads: video ≤ 95 MB, zip ≤ 50 MB, html ≤ 2 MB, image ≤ 5 MB. - Voiceover text ≤ 1500 characters; 5 AI voiceovers and 20 Post Kits per day via agents.
- 200 renders per month per account, shared with the website.
- 120 requests per minute per token.
Uploading local files
# 1. create_upload { filename: "demo.mp4" } → { upload_id, upload_url }
curl -T demo.mp4 -H "Content-Type: application/octet-stream" "<upload_url>"
# 2. render { upload_id, music_url, captions: true }
Upload links work once and expire after an hour. An upload_id stays usable if a render is refused, so you can fix the request and retry.
Errors
Tool failures come back as a normal tool result with isError: true and a structured body { "error": "…", "busy"?: true, "retry_after_sec"?: n }. The message says what to change. Protocol-level problems use JSON-RPC errors: -32700 parse error, -32600 invalid request, -32601 unknown method, -32602 unknown tool, -32001 authentication required (HTTP 401), -32000 rate limited (HTTP 429, Retry-After header).
Security and privacy
- Tokens and keys are stored hashed and can be revoked by the user at any time.
- Animations render in an isolated headless browser that can reach the public internet but not private networks or cloud metadata.
- Download links are signed and expire after 24 hours. Rendered files are kept for 32 days.
- Uploaded files are used only to produce the requested video. Music comes from Freesound (CC0). AI voiceover and Post Kits use Google Gemini, with a local fallback voice. Captions use a self-hosted speech-recognition model.
- Privacy policy: https://animation-machine.com/privacy · Terms: https://animation-machine.com/terms
Discovery
- Server card:
https://animation-machine.com/.well-known/mcp/server-card.json - Official MCP Registry:
com.animation-machine/animation-machine - Docs and examples: https://github.com/dssdave/animation-machine-mcp
- Support: [email protected]