Skip to content
MCPBytes
DocsAnimate a 3D model

Tool reference · 3D Models

Animate a 3D model

Add one animation clip, generated from a description, to a rigged humanoid model, with motion checks and a preview.

MCP tool
animate_3d_model
MCP endpoint
/mcp/3d
REST
POST /v1/tools/animate_3d_model/jobs
Price
20 credits per job

Overview

Send a rigged humanoid GLB (one skeleton with two legs, two arms and a head) and a description of a motion. The motion is generated for a standard human body and transferred onto your skeleton: bone roles are found from the skeleton's shape, the character's own facing and proportions are kept, and feet that touch the ground are kept planted and on the floor. The file comes back unchanged except for one added animation, 1 to 10 seconds at 30 frames per second; earlier animations are replaced. motion.json lists the bone roles, facing, travel and foot contacts; motion_report.json gives the status (passed, needs_review or failed_checks) and each issue with its frames; motion_preview.png shows six moments from the front and the side. A succeeded job means the motion was written, not that it looks right. Start the job, keep its id and poll: it takes a few minutes.

Formats
.glb with one skeleton: two legs, two arms and a head (a rig from Rig a 3D model, or from any other tool)
Outputs
model.glb (the same model with one animation), motion.json, motion_report.json, motion_preview.png and generation.json
Motion
1 to 10 seconds at 30 frames per second, travelling or in place
Checks
Planted feet sliding or floating, the model going through the floor, sudden bone turns
Duration
Asynchronous; one-hour deadline including queueing and execution

Quickstart

Send the file as the request body with the options in the query string, or refer to it in a JSON body (upload_id or url) with an options object. The response is the new job; poll it until its status is final, then download the files in result.files.

Start a jobanimate.sh
# idempotency_key is required: repeating it returns the same job
curl https://api.mcpbytes.com/v1/tools/animate_3d_model/jobs \
  -H "Authorization: Bearer $MCPBYTES_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "job_file": {"job_id": "j_...", "name": "model.glb"},
    "options": {
      "description": "A person walks forward confidently.",
      "duration": 5,
      "seed": 42
    },
    "idempotency_key": "animate-example-001"
  }'
Response202 Accepted · trimmed
{
  "tool": "animate_3d_model",
  "status": "queued",
  "input_kind": "file",
  "workflow": {
    "stage": "Animating",
    "deadline": "2026-09-27T23:21:27.662Z",
    "cancel_pending": false,
    "refund_pending": false
  },
  "capabilities": {
    "can_cancel": true
  },
  "options": {
    "description": "A person walks forward confidently.",
    "duration": 5,
    "in_place": false,
    "seed": 42
  },
  "result": null
}
Get the resultread.sh
# JOB_ID is the id from the create response; poll until status is final
curl "https://api.mcpbytes.com/v1/jobs/$JOB_ID" \
  -H "Authorization: Bearer $MCPBYTES_API_KEY"

# Once status is succeeded, download each file from result.files[].url
curl -fsSLo model.glb "$MODEL_URL"
Response200 OK · trimmed
{
  "tool": "animate_3d_model",
  "status": "succeeded",
  "result": {
    "notes": [],
    "duration": 5,
    "frames": 150,
    "status": "passed",
    "issues": [],
    "files": [
      {
        "name": "model.glb",
        "bytes": 15060048,
        "content_type": "model/gltf-binary",
        "url": "https://api.mcpbytes.com/blob/dl/…"
      },
      {
        "name": "motion.json",
        "bytes": 3168,
        "content_type": "application/json",
        "url": "https://api.mcpbytes.com/blob/dl/…"
      },
      {
        "name": "motion_report.json",
        "bytes": 580,
        "content_type": "application/json",
        "url": "https://api.mcpbytes.com/blob/dl/…"
      },
      {
        "name": "motion_preview.png",
        "bytes": 252926,
        "content_type": "image/png",
        "url": "https://api.mcpbytes.com/blob/dl/…"
      },
      {
        "name": "generation.json",
        "bytes": 2323,
        "content_type": "application/json",
        "url": "https://api.mcpbytes.com/blob/dl/…"
      }
    ]
  },
  "compute_ms": 27551,
  "credits_charged": 20
}

Jobs of this tool take minutes. While one runs, workflow.stage says what is happening and workflow.deadline when it must finish. Cancel it with POST /v1/jobs/{id}/cancel while capabilities.can_cancel is true.

More on statuses, downloads and retention in Jobs & files.

Input

One file per job, in one of these ways. The formats it accepts are listed in the overview.

Input sources
File body
REST only: the file itself as the request body, with ?filename= and the options in the query string.
upload_id
Create an upload URL (POST /v1/uploads, or create_upload over MCP), PUT the file to it, then pass the upload_id. Upload URLs expire after an hour.
url, filename
A public https URL. Add filename when the URL does not end in the file's extension.
job_file
{job_id, name}: an output of one of your own completed jobs that has not expired. It is copied into the new job, with no download in between.
# 1. Create an upload URL (valid for one hour)
curl https://api.mcpbytes.com/v1/uploads \
  -H "Authorization: Bearer $MCPBYTES_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"filename": "model.glb"}'

# 2. PUT the file to the "url" from the response
curl -X PUT --data-binary @model.glb "$UPLOAD_URL"

# 3. Start the job with the "upload_id"
curl https://api.mcpbytes.com/v1/tools/animate_3d_model/jobs \
  -H "Authorization: Bearer $MCPBYTES_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"upload_id\": \"$UPLOAD_ID\",
    \"options\": {
      \"description\": \"A person walks forward confidently.\",
      \"duration\": 5
    },
    \"idempotency_key\": \"animate_3d_model-upload-001\"
  }"
idempotency_key is required. Repeating a request with the same key returns the original job instead of starting and charging a new one; reusing a key for a different request returns 409 idempotency_conflict. With a file body, send the key as an Idempotency-Key header.

Options

Put options in the query string when the file is the request body, in the options object of a JSON body, or pass them as arguments of the MCP tool. Leave an option out to use its default.

Options
description
text, 3 to 500 charactersThe motion, best as "A person…" with one or two actions. Required; kept out of generation.json.
duration
1 – 10 secondsLength of the clip. Default 4.
in_place
true · falseKeep the character on the spot instead of travelling. Default false.
seed
integer 0 – 4294967295Reproducible within the same tested runtime; another seed gives another take. Random when omitted.

Outputs

A succeeded job lists its files in result.files, each with a download url.

Output files
model.glb
The input model with one added animation named "animation": keys at 30 frames per second on the skeleton's rotations and the hips' position. Mesh, textures and skeleton are unchanged; earlier animations are replaced.
motion.json
What was made and how it maps onto the rig: frames, fps, duration, in_place, the model's facing, the hips' travel, each role's bones, and each foot's contacts (heel or toes, frames).
motion_report.json
status, the thresholds used, the measurements (per foot: contacts, largest slide and float; floor depth; largest bone turn per frame and its change) and the issues, each with frames, value, threshold and severity.
motion_preview.png
1536 × 512 image: six moments of the animated model from its own front and its own side, with the skeleton drawn over it.
generation.json
Provenance: your options except the description, and the animation step's version, summary and timings.

Download links last up to 24 hours, capped by output retention; read the job again for fresh links. A succeeded job means the motion was written; whether it looks right is in motion_report.json and motion_preview.png.

Result summary

Next to files, the job's result has a summary you can check without downloading anything:

result
duration, frames
Length of the clip in seconds, and its frames at 30 per second.
status
The report's verdict: passed, needs_review or failed_checks.
issues
The report's first five issues: type, side or bone, frames, value, threshold, severity.

Tips

  • Describe the motion as "A person…" with one or two actions: "A person walks forward confidently", "A person waves with their right hand". Everyday movement, gestures, dancing and fighting work best.
  • Send the description in the JSON body or as MCP arguments, never in a URL.
  • Pass model.glb of a rig_3d_model job as job_file. A model rigged elsewhere works too, as long as its skeleton has two legs, two arms and a head.
  • Read motion_report.json and look at motion_preview.png before using the clip. If it fails its checks, try another seed or wording; each job is charged.
  • in_place keeps the character on the spot, for a clip your engine moves itself; otherwise it travels as it walks or runs.
  • Motions on the ground (sitting, kneeling) can push a tail or long clothes through the floor; the report says so.

MCP

Your agent calls animate_3d_model. Connect it to https://api.mcpbytes.com/mcp/3d for this tool and the rest of its family (Create a 3D model, Create a 3D model from an image, Optimize a 3D model, Simplify a 3D model, Rig a 3D model, Split a 3D model into parts, Inspect a 3D model), or to https://api.mcpbytes.com/mcp for every tool.

Claude Code

The first form signs in through the browser when you run /mcp. In .mcp.json (project root), ${MCPBYTES_API_KEY} is read from the environment when Claude Code connects. Claude Code docs

claude mcp add --transport http mcpbytes \
  https://api.mcpbytes.com/mcp/3d
Codex (CLI, IDE extension, ChatGPT desktop)

Codex reads the key from the environment variable each time it connects. The same table can go in ~/.codex/config.toml by hand; codex mcp add has no --header flag. Codex docs

codex mcp add mcpbytes --url https://api.mcpbytes.com/mcp/3d \
  --bearer-token-env-var MCPBYTES_API_KEY
Cursor

~/.cursor/mcp.json (all projects) or .cursor/mcp.json (one project). Remote servers take no "type". Without the header, the client signs you in with GitHub or an email link (OAuth). Cursor docs

~/.cursor/mcp.json
{
  "mcpServers": {
    "mcpbytes": {
      "url": "https://api.mcpbytes.com/mcp/3d",
      "headers": {
        "Authorization": "Bearer ${env:MCPBYTES_API_KEY}"
      }
    }
  }
}
11 more clients in the docs →

Arguments

The tool's options are flat arguments. Besides them:

animate_3d_model arguments
upload_id
From create_upload, after the agent has PUT the file.
url, filename
A public https URL, and the file name when the URL does not end in the extension.
job_file
{job_id, name}: an owned output of an earlier job.
wait_seconds
0–45, default 0How long the call waits for the result. If the job is still running, the agent calls get_job.
idempotency_key
RequiredReuse it with the same arguments when retrying after a network error.

What the agent sees

MCP tools
animate_3d_model
Animates a rigged humanoid GLB (two legs, two arms and a head, e.g. model.glb of a rig_3d_model job) from a description of a motion such as "A person walks forward confidently". Adds one animation clip, up to 10 seconds at 30 frames per second, to the model's own file: its mesh, textures and skeleton are unchanged. Planted feet stay where they land and on the floor. Accepts one self-contained, uncompressed GLB with one skeleton, up to 1,000,000 triangles. Returns model.glb (animated), motion.json (bone roles, facing, travel, foot contacts), motion_report.json (foot sliding, floating, floor penetration and rotation pops; status passed, needs_review or failed_checks) and motion_preview.png. Works best on everyday movement, gestures, dancing and combat, described as "A person…". A succeeded job means the motion was written, not that it looks right: read motion_report.json and look at motion_preview.png. This is an asynchronous job; use get_job to follow progress. A failed job is refunded. Costs 20 credits per job. Requires idempotency_key; retain it when retrying the same request.
create_upload
Returns a one-hour URL to PUT a local file to; then call the tool with the upload_id.
get_job
Status and results of a job; waits up to wait_seconds for it to finish.
cancel_job
Cancel a queued job or a workflow whose can_cancel is true; repeated calls never delete results.
list_jobs
Your most recent jobs, newest first.
read_job_file
Reads a text output (.txt .json .md .csv) of a succeeded job in chunks.

Setup for every client, and how agents upload files and read results: Connect over MCP.

Agent skill

The MCPBytes skill teaches agents this tool, in references/animate_3d_model.md. Agents without MCP run it through the REST API with the skill's script, which reads your key from MCPBYTES_API_KEY:

mcpbytes.py
printf '{"description": "A person waves with their right hand.",
  "duration": 4}' > options.json
python scripts/mcpbytes.py run animate_3d_model \
  --job-file j_... model.glb \
  --options-json options.json --out animated/

Pricing

20 credits per job. The price is charged before paid processing starts, and a canceled job is refunded. A job that fails costs nothing: its charge is refunded.

Per job
20 credits

One credit balance pays for every tool, and a new account starts with free credits. See Credits & prices or buy credits.

Limits

Limits
Jobs
20 per rolling 24 hours; 3 until your first credit purchase
Model
Up to 50 MB and 1,000,000 triangles
At a time
1 job
Uploads
Up to 50 MB
Results
24 hours by default

GET /v1/me returns your limits and current usage; Limits & errors explains what happens when one is reached.

Errors

A failed job comes back with error.code, error.message and often error.hint. Codes are stable. Inputs that fail with a validation error will fail again unchanged.

Job errors
invalid_mesh
Not a readable, self-contained GLB.
limit_exceeded
More than 1,000,000 triangles.
too_large
HTTP 413 at creation: the file is larger than your plan's upload size.
unsupported_rig
No skeleton, several skeletons, over 256 joints, or no humanoid found (two legs, two arms and a head). Refused before any charge.
inference_failed
The motion could not be made. Try again with another seed or wording. Any charge is refunded.
timeout
The job did not finish within its deadline. Any charge is refunded.
capacity_exhausted
Budget exhausted: HTTP 503 at creation, or a failed job if the budget ran out before charging. Try again later.
unsupported_format
The tool does not take this file type.
insufficient_credits
The job costs more than the balance, which is known once the input has been measured. Nothing was charged.
out_of_memory
The file needs more memory than a job has.

Requests can also fail before a job starts, with an HTTP status: see HTTP errors.