Animation Machine / MCP server / Docs

Animation Machine MCP server docs

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:

  1. The agent writes a self-contained HTML animation, or picks a template.
  2. preview_frame returns one still frame so the agent can check its work.
  3. render plays 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.
  4. The agent polls get_job and 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".

EndpointURL
Protected resource metadatahttps://animation-machine.com/.well-known/oauth-protected-resource
Authorization server metadatahttps://animation-machine.com/.well-known/oauth-authorization-server
Authorizationhttps://animation-machine.com/oauth/authorize
Tokenhttps://animation-machine.com/oauth/token (form-urlencoded or JSON)
Dynamic client registrationhttps://animation-machine.com/oauth/register
Revocationhttps://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 files or 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 pass duration_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.

ParameterTypeRequiredDescription
htmlstringA complete, self-contained HTML page with the animation (inline CSS/JS; CDN <script>/<link> tags are fine). Max 2 MB.
filesobjectA multi-file project: {"index.html": "...", "style.css": "...", "img/logo.png": {"base64": "..."}}. Max 5 MB total.
upload_idstringA .zip / .html / video file uploaded with create_upload.
aspectsarray 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.
fps24 | 30Default 30.
duration_secondsnumberForce 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_countintegerRepeat the animation N times. Default 1. (min 1, max 3)
crop_to_fillbooleanCrop a 16:9 design to fill 9:16 or 1:1 instead of letterboxing.
music_urlstringBackground music: a track "url" from search_music.
music_volumenumberMusic volume 0–1. Default 0.15 (bed under voice). Use ~0.6 when there is no voiceover. (min 0, max 1)
music_fadebooleanFade the music in and out. Default true.
voiceover_textstringNarration script, spoken by an AI voice and mixed in. Max 5 per day via agents. (≤ 1500 chars)
voiceover_voicestringVoice id from list_voices. Default "Kore".
voiceover_speednumberDefault 1.0. (min 0.5, max 2)
captionsbooleanBurn 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_overlaystringA small corner stamp like "@yourhandle". (≤ 60 chars)
intro_titlestringAdd a 3-second title card before the animation. (≤ 80 chars)
intro_subtitlestring(≤ 120 chars)
outro_titlestringAdd a 3-second end card, e.g. "Try it free at example.com". (≤ 80 chars)
outro_subtitlestring(≤ 120 chars)
logo_upload_idstringA 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.

ParameterTypeRequiredDescription
template"title_card" | "lower_third" | "quote" | "stat"yes
fieldsobjectyesTemplate fields (which ones apply depends on the template, see the description).
fields.titlestringtitle_card: the headline
fields.subtitlestringtitle_card: optional second line
fields.namestringlower_third: person or brand name
fields.rolestringlower_third: optional role/title
fields.quotestringquote: the quote text
fields.authorstringquote: optional attribution
fields.valuenumberstat: the number to count up to
fields.prefixstringstat: e.g. "$"
fields.suffixstringstat: e.g. "%" or "+"
fields.labelstringstat: text under the number
fields.accent_colorstringHex color, e.g. "#7c5cff"
fields.backgroundstringHex color
fields.durationnumberSeconds
aspectsarray 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.
fps24 | 30Default 30.
loop_countintegerRepeat the animation N times. Default 1. (min 1, max 3)
crop_to_fillbooleanCrop a 16:9 design to fill 9:16 or 1:1 instead of letterboxing.
music_urlstringBackground music: a track "url" from search_music.
music_volumenumberMusic volume 0–1. Default 0.15 (bed under voice). Use ~0.6 when there is no voiceover. (min 0, max 1)
music_fadebooleanFade the music in and out. Default true.
voiceover_textstringNarration script, spoken by an AI voice and mixed in. Max 5 per day via agents. (≤ 1500 chars)
voiceover_voicestringVoice id from list_voices. Default "Kore".
voiceover_speednumberDefault 1.0. (min 0.5, max 2)
captionsbooleanBurn 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_overlaystringA small corner stamp like "@yourhandle". (≤ 60 chars)
intro_titlestringAdd a 3-second title card before the animation. (≤ 80 chars)
intro_subtitlestring(≤ 120 chars)
outro_titlestringAdd a 3-second end card, e.g. "Try it free at example.com". (≤ 80 chars)
outro_subtitlestring(≤ 120 chars)
logo_upload_idstringA 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.

ParameterTypeRequiredDescription
htmlstringA complete, self-contained HTML page with the animation (inline CSS/JS; CDN <script>/<link> tags are fine). Max 2 MB.
filesobjectA multi-file project: {"index.html": "...", "style.css": "...", "img/logo.png": {"base64": "..."}}. Max 5 MB total.
upload_idstringA .zip / .html / video file uploaded with create_upload.
at_secondsnumberTime 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_secondsnumberForce 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.

ParameterTypeRequiredDescription
job_idstringyes

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.

ParameterTypeRequiredDescription
job_idstringyes

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.

ParameterTypeRequiredDescription
filenamestringyese.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.

ParameterTypeRequiredDescription
querystringyes

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.

ParameterTypeRequiredDescription
job_idstringyes
contextstring(≤ 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)

TemplateWhat it isFields
title_cardBig 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_thirdName + 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)
quoteA 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)
statA 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

StatusMeaning
queuedWaiting for the render server (queue_position given)
renderingIn progress (progress_pct given)
scheduledA later aspect ratio of a multi-aspect request, waiting for the previous one
doneFinished: 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)
errorFailed: error explains why; error_code may be DURATION_UNKNOWN (pass duration_seconds) or TOO_LONG
cancelled / failedCancelled, 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: true and retry_after_sec.
  • If the agent queue is full, calls return busy: true with retry_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