move-api-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., "@move-api-mcp Upload my dance video and run a single-cam job"
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.
move-api-mcp
A local MCP server for the Move AI UGC GraphQL API
(https://api.move.ai/ugc/graphql). It gives Claude Code, Claude Desktop, Cursor and any
other MCP client typed tools for the markerless mocap pipeline — upload footage, create
takes, run single- and multi-camera jobs, poll progress and pull the output files down.
Transport: stdio (runs locally, nothing is exposed on the network)
Auth: API key (
Authorization: mv_key_…) or JWT bearer (Authorization: Bearer …)Mutations are refused unless writes are explicitly enabled — mocap jobs are billable
Schema reference: https://move-ai.github.io/move-ugc-api/ · docs: https://developers.move.ai/docs/api-reference
Install
git clone <this repo> && cd move-api-mcp
# with a venv (no extra tooling needed)
python -m venv .venv
.venv/bin/pip install -e '.[dev]'
.venv/bin/move-api-mcp --version
# or with uv, if you have it
uv sync
uv run move-api-mcp --versionRequires Python 3.11+. Whichever you pick, note the absolute path of the launcher —
.venv/bin/move-api-mcp or uv — because MCP clients need it below.
Related MCP server: Magic Hour MCP Server
Configure
Copy .env.example and set one credential:
Variable | Default | Purpose |
| — | API key from dev.move.ai. Sent verbatim: |
| — | JWT / OAuth access token. Sent as |
| — | Alias for either; the scheme is auto-detected from the token shape |
|
| Use |
|
|
|
|
| Must be |
|
| HTTP timeout in seconds |
|
| Upload size ceiling |
| unset | When set, downloads may only be written inside this directory |
Precedence for the credential is MOVE_API_JWT → MOVE_API_TOKEN → MOVE_API_KEY.
auto sends Bearer for JWT-shaped tokens (three dot-separated segments) and the raw
value for Move API keys, which the API expects without a scheme prefix.
CLI flags override the environment: --endpoint, --auth-scheme, --allow-writes,
--read-only.
Register with an MCP client
Claude Code
Substitute your own checkout path for /path/to/move-api-mcp — claude mcp add will
happily register the placeholder, and the server then fails to start.
# venv install
claude mcp add move-api \
--env MOVE_API_KEY=mv_key_… \
-- /path/to/move-api-mcp/.venv/bin/move-api-mcp
# uv install
claude mcp add move-api \
--env MOVE_API_KEY=mv_key_… \
-- uv --directory /path/to/move-api-mcp run move-api-mcpRe-registering under a name that already exists is refused, so change it with
claude mcp remove move-api followed by a fresh add. claude mcp get move-api
shows what is currently registered.
Claude Desktop / Cursor (claude_desktop_config.json, .cursor/mcp.json)
{
"mcpServers": {
"move-api": {
"command": "/path/to/move-api-mcp/.venv/bin/move-api-mcp",
"env": {
"MOVE_API_KEY": "mv_key_…",
"MOVE_API_ALLOW_WRITES": "false"
}
}
}
}Enable writes only when you intend to spend processing credits:
"env": { "MOVE_API_KEY": "mv_key_…", "MOVE_API_ALLOW_WRITES": "true" }Check it works by asking the client to call move_client_info — it returns the account
the credential belongs to, the endpoint, the auth scheme in use and whether writes are on.
Tools
Read-only (always available):
Tool | What it does |
| Current account + effective server config |
| File details and a fresh presigned URL |
| Stream a file to local disk |
| Takes, with |
| Jobs, state and |
| Pull every (or selected) output of a finished job |
| Multicam calibration volumes |
| Available skeleton rigs |
| Supported camera lens ids |
Mutating (need MOVE_API_ALLOW_WRITES=true):
Tool | What it does |
| Reserve a file and get a presigned PUT URL |
| Create and upload a local video in one step |
| Rename / set metadata |
| Group footage into a take |
| Start mocap processing (billable) |
| Calibrate a multicam rig from footage of a person (billable) |
| Shareable link for an output file |
| Set account metadata |
| Create/update a webhook subscription |
Escape hatch: move_graphql runs an arbitrary document for fields the typed tools do not
cover. Mutations detected in it are gated the same way.
expand arguments mirror move-ugc-python's: pass ["outputs"], ["take", "inputs"],
["sources", "volume"] and so on to pull nested objects in a single round trip.
Workflows
Single camera
move_upload_file— the.mp4(plus the matching.movefile for Move One footage; both share adevice_label)move_create_single_cam_takewith those file idsmove_create_single_cam_jobwith the take idPoll
move_get_jobuntilstateisFINISHED(NOT_STARTED → STARTED → RUNNING → FINISHED/FAILED)move_download_job_outputs
Multi camera
move_list_camera_settings— find each camera's lens idmove_upload_fileper calibration clip →move_create_volume_with_human(needs the performer's height in metres)Poll
move_get_volumeuntilFINISHEDmove_upload_fileper action clip →move_create_multi_cam_takewith the volume id, re-using the samedevice_labels and lensesmove_create_multi_cam_job→ poll → download
Design notes
AWSJSON— the API'smetadatafields carry JSON as a string. Tools take a normal JSON object and encode/decode it for you;move_graphqldoes not (pass strings there).Pagination — list tools return
{items, count, next_cursor}; feednext_cursorback asafter.Presigned URLs — short-lived, and the same field is an upload target on input files and a download link on outputs. Fetch them at the point of use.
Uploads stream in 8 MiB chunks with an explicit
Content-Length, so large takes don't sit in memory and S3 doesn't reject chunked encoding.Errors — GraphQL errors are surfaced with the Move error code (
MV_010_010_0001) and any suggestions attached; a 401/403 says which header format was sent.Downloads are confined to
MOVE_API_DOWNLOAD_DIRwhen it is set, and never overwrite withoutoverwrite=true.
Development
pip install -e '.[dev]'
pre-commit install # mandatory before committing
pytest # unit tests
pytest --cov # with coverage (fails under 90%)
ruff check . && ruff format --check .
mypy src
# stdio handshake against the real MCP client SDK — no Move API call is made
MOVE_API_KEY=mv_key_dummy python scripts/smoke_stdio.pyThe transport is exercised through httpx.MockTransport; no test touches the real API.
src/move_api_mcp/
config.py env -> Settings, credential + auth-scheme resolution
client.py GraphQL/HTTP transport, AWSJSON encoding, upload + download
errors.py Move error codes and suggestions
graphql.py documents and expandable selection sets
models.py typed tool inputs (Source, SyncMethod, JobOptions, ClipWindow)
server.py MCPServer assembly, instructions, lifespan
tools/ one module per resource: catalog, files, takes, jobs, volumes,
webhooks, rawBuilt against the MCP Python SDK 2.x (MCPServer).
Security
The credential is read from the environment only — never committed, never logged (
describe()redacts it, and status output goes to stderr, not the MCP stdout channel).Writes are off by default so an agent cannot start billable jobs by accident.
secretonmove_upsert_webhook_endpointis a credential: treat tool output as sensitive.Presigned URLs in responses grant temporary access to the underlying object — avoid pasting them into shared transcripts.
However you register the server, the key is stored in plaintext in the client's config (
~/.claude.jsonfor Claude Code), so treat that file as a secret. Passing it as-e MOVE_API_KEY="$MOVE_API_KEY"from an exported variable keeps it out of your shell history, which an inline literal does not. Rotate any key that has been pasted into a terminal or a chat.
Available Tools
26 toolsmove_client_infoARead-only
Return the Move API client (account) the current credential belongs to.
Use this first to confirm the server is authenticated against the expected account and endpoint.
Inputs: no named parameters. Returns: object
move_create_fileA
Reserve a file slot and get a presigned PUT URL to upload the bytes to.
Prefer move_upload_file when the video is on this machine — it does the
create and the upload in one step.
Inputs: file_type (required), name, metadata. Returns: object
move_create_multi_cam_jobA
Start a multi-camera mocap job. This consumes processing credits.
Inputs: take_id (required), name, expand, options, +4 more. Returns: object
move_create_multi_cam_takeA
Create a multi-camera take against an existing calibration volume.
Inputs: sources (required), volume_id (required), name, expand, +2 more. Returns: object
move_create_single_cam_jobA
Start a single-camera mocap job. This consumes processing credits.
Inputs: take_id (required), name, expand, options, +3 more. Returns: object
move_create_single_cam_takeA
Create a single-camera take from already-uploaded files.
Inputs: sources (required), name, expand, metadata. Returns: object
move_create_volume_with_humanA
Calibrate a multicam setup from footage of a person of known height.
This is step one of the multicam workflow and consumes processing credits.
Poll move_get_volume until state is FINISHED, then create a multicam take
with the same device_labels and lenses.
Inputs: sources (required), human_height (required), name, expand, +4 more. Returns: object
move_download_fileCIdempotent
Download a Move file (typically a job output) to this machine.
Inputs: file_id (required), dest_path, overwrite. Returns: object
move_download_job_outputsAIdempotent
Download every output file of a FINISHED job to this machine.
Inputs: job_id (required), keys, dest_dir, overwrite. Returns: object
move_get_fileARead-only
Fetch a file, including a fresh presigned URL.
For input files the presigned URL is an HTTP PUT upload target; for job output files it is a time-limited download URL.
Inputs: file_id (required). Returns: object
move_get_jobARead-only
Fetch a job, including its state and percentage progress.
States: NOT_STARTED, STARTED, RUNNING, FINISHED, FAILED. Poll this rather than blocking; processing typically takes minutes.
Inputs: job_id (required), expand. Returns: object
move_get_takeARead-only
Fetch a take by id.
Inputs: take_id (required), expand. Returns: object
move_get_volumeARead-only
Fetch a calibration volume and its processing state.
A volume must reach state FINISHED before it can back a multicam take.
Inputs: volume_id (required), expand. Returns: object
move_graphqlA
Run an arbitrary GraphQL document against the Move API.
Use the typed tools first; this is for fields they do not expose. Mutations still require writes to be enabled. Schema reference: https://move-ai.github.io/move-ugc-api/
Inputs: query (required), variables. Returns: object
move_list_camera_settingsARead-only
List supported camera lens ids for Source.camera_settings.lens.
Multicam accuracy depends on declaring the lens each camera used.
Inputs: no named parameters. Returns: object
move_list_jobsCRead-only
List jobs, optionally filtered to one take.
Inputs: after, first, expand, take_id, +1 more. Returns: object
move_list_rigsARead-only
List the skeleton rigs available to this account.
Inputs: no named parameters. Returns: object
move_list_takesBRead-only
List takes, newest first when sort_direction=DESC.
Inputs: after, first, expand, sort_direction. Returns: object
move_list_volumesCRead-only
List calibration volumes.
Inputs: after, first, expand, sort_direction. Returns: object
move_update_clientAIdempotent
Replace the metadata object stored on the client (account).
Inputs: metadata (required). Returns: object
move_update_fileBIdempotent
Update a file's name and/or metadata.
Inputs: file_id (required), name, metadata. Returns: object
move_update_jobAIdempotent
Update a job's name and/or metadata.
Inputs: job_id (required), name, expand, metadata. Returns: object
move_update_takeCIdempotent
Update a take's name and/or metadata.
Inputs: take_id (required), name, expand, metadata. Returns: object
move_upload_fileA
Create a Move file and upload a local video to it in one step.
Returns the file id to pass as Source.file_id when creating a take or volume.
Inputs: local_path (required), name, metadata, file_type. Returns: object
move_upsert_webhook_endpointAIdempotent
Create or update a webhook endpoint for this client.
Inputs: uid (required), url (required), events, secret, +2 more. Returns: object
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 26 tools
Tools are mostly organized by resource and action, making takes, jobs, volumes, and files easy to distinguish. The only real confusable pairs are create_file/upload_file and get_file/download_file, though their descriptions clarify the intended use.
Nearly every tool follows a clear move_<verb>_<noun> pattern with consistent snake_case. Minor deviations like move_client_info and move_graphql break the pattern slightly, but the overall style is predictable.
With 26 tools, the server is on the heavy side, and the many file/job variants make the surface feel crowded. However, the tools map to a genuinely broad API spanning clients, files, takes, jobs, volumes, and webhooks, so the count is not an extreme mismatch.
The core file-to-take-to-job-to-output workflow is well covered, including multicam volume calibration and webhook setup. Notable gaps remain: there is no list-files tool, no delete/cancel operations for takes or jobs, and volume update/delete coverage is absent.
Maintenance
Related MCP Connectors
Control Unreal Engine to browse assets, import content, and manage levels and sequences. Automate…
Create and manage cinematic AI video renders through the Future Video Studio Agent API.
Run any Relay model (image, video, audio, LLM), poll tasks, upload files and search Relay's docs.
Make images and videos, price requests, list AI models and read your balance, from one API key.
Related MCP Servers
- AlicenseBqualityBmaintenanceEnables creating and polling Luma video modification tasks, fetching task status, and checking pricing via the RunAPI API.374 npmApache 2.0

Magic Hour MCP Serverofficial
AlicenseAqualityCmaintenanceEnables image, video, and audio generation via Magic Hour's API, including async polling, file uploads, and project downloads.459Apache 2.0- FlicenseAqualityCmaintenanceEnables discovering and invoking all 97 published Frame.io V4 API operations through a searchable catalog, covering accounts, projects, folders, files, comments, shares, metadata, webhooks, and more using OAuth credentials. It also performs complete local multipart uploads, including chunked PUTs and upload status checks.5-

CraftStory MCP Serverofficial
AlicenseAqualityBmaintenanceEnables MCP clients to create talking-avatar videos of any length from a photo plus audio, and short AI clips with generated sound or lip-sync, through the CraftStory API. It also covers voice and avatar listing, speech generation, cost previews, job status and result retrieval, and upscaling.11109 npmMIT