motion-mcp-server
MCP server for reading and editing Apple Motion template files (.motn/.moti), enabling inspection and modification of layers, parameters, keyframes, and publish settings, plus saving and validation.
README
motion-mcp-server
An MCP server for reading and editing
Apple Motion (.motn / .moti) template files.
Scope — read this first
This server edits static template XML on disk. It does not, and cannot, drive a live Motion.app session.
Final Cut Pro exposes a rich AppleScript/Apple Events dictionary, which is
what makes a "live control" MCP server (see
fcp-mcp-server, the project
that inspired this one's architecture) possible for FCP. Apple Motion's own
scriptability is limited to three verbs: activate, open, quit. There is
no dictionary for pushing parameter values, scrubbing the playhead, or
reading back rendered frames from a running Motion document.
So this server's actual capability is: parse a .motn/.moti file (both are
the same ozml XML format Motion.app itself writes), let you inspect and
mutate its layer/parameter/keyframe/publish-settings tree, and save the
result to a new file. Getting the result on screen means opening the written
file in Motion.app yourself — motion_open_in_motion does that handoff — or
handing a published/rendered template to Final Cut Pro, which does have the
rich Apple Events surface (see the sibling fcpxml/commandpost MCP
servers for that half of a pipeline).
What it can do
Five tool groups, 17 tools:
- inspect —
motion_open,motion_list_layers,motion_list_text_layers,motion_get_parameter,motion_list_keyframes,motion_list_rig - animate —
motion_set_text,motion_set_parameter_value,motion_set_color,motion_create_keyframe_curve,motion_add_keyframe - structural —
motion_clone_layer(duplicate an existing<layer>subtree in place — see "Adding new layers" below) - rig —
motion_publish_parameter,motion_unpublish_parameter(Final Cut Pro's Inspector reads these published/rig parameters when the template is used as an FCP title/generator/effect) - deliver —
motion_save_as,motion_open_in_motion,motion_validate
Authoring motion from scratch
motion_create_keyframe_curve seeds a brand-new <curve> on a leaf
parameter that has never been keyframed in Motion — actual dynamic/
procedural animation authoring, not just editing curves Motion already
created. This was initially considered too risky to guess at (a curve's
type attribute is data-type-specific, and guessing wrong produces a file
Motion can't open), so it's grounded in a structural scan of ~4,700 real
Motion documents on the machine this was built on: every keyframed leaf
parameter observed — Position X/Y/Z, Scale, Angle/Rotation, Opacity, RGB(A)
color channels, behavior Amount parameters — used the same universal
scalar curve (type="1"), because Motion animates a compound property
(Position, Color, ...) by keyframing each numeric child parameter
independently rather than through one multi-component curve. A second curve
type ("0") does exist on some non-numeric/enum-like parameters (Random
Seed, Blend Mode, Interpolation) but never carried an actual keypoint in
that scan, so this tool deliberately doesn't attempt to synthesize it —
there's no real-file evidence for what a keyed type="0" curve should look
like. Verified against both the synthetic fixture and an ephemeral,
never-committed round-trip against a real local .motn file.
Once a parameter has a curve — whether Motion created it or
motion_create_keyframe_curve did — motion_add_keyframe appends further
keypoints to it, in time order.
Adding new layers
motion_clone_layer duplicates an existing <layer> subtree (including any
nested child layers, e.g. a Group's children) and inserts the copy as the
next sibling of the original. This is the supported way to add new
structure to a template — it's a clone, not a from-scratch synthesizer,
and that's a deliberate, evidence-based choice, not a missing feature.
A structural scan of real Motion documents (same discipline as the curve
work above) found two reasons hand-authoring a brand-new layer from scratch
is materially riskier than editing an existing one: a Text-layer scenenode
tree is far deeper than any parameter this server otherwise touches
(paragraph/scroll/crawl margins, per-run styles, cross-referencing <host>
links), and the numeric factoryID for the same semantic kind (e.g.
"Text") is not stable across documents — it varied across every
personal .motn/.moti file scanned. Hardcoding a factory id would
silently produce a file that opens fine in the document it was copied from
and fails to open, or resolves to the wrong factory, in another.
Cloning sidesteps both problems: the subtree being duplicated is already
valid, real, Motion-authored XML from the same document, so nothing about
its factory graph needs to be guessed. The only thing motion_clone_layer
actually computes is id remapping — every layer/scenenode id inside the
cloned subtree is reassigned to a freshly allocated, document-unique value
(scanned across the entire document, not just the subtree, so it can
never collide with anything already present), and any <host hostID="...">
link that points inside the cloned subtree is rewritten to match. A
<host> link pointing outside the clone — an intentional cross-reference
to an unrelated part of the document — is left untouched, since remapping
it would silently break that reference. Verified against the synthetic
fixture (including a nested-group case exercising both the internal- and
external-<host> fixup paths) and two ephemeral, never-committed
round-trips against real local .motn files — one a flat layer, one a
layer with a nested child.
The ozml schema
Ground truth for the tag shapes this server relies on was read directly from
real Motion.app output on the machine this was built on (Motion Projects/Autosave Vault/*.motn, Motion Templates.localized/*.moti), not
assumed. See the module docstring in motion/parser.py for the annotated
shape, including two nesting traps that are easy to get wrong by guessing:
- Top-level layers are direct children of
<scene>, not<timeline>(<timeline>in this schema is only a UI display-state block). - Text face/outline/glow color and font live under a
<style>element that's a sibling of a scenenode's<parameter>tree, not nested inside it.
No personal .motn/.moti file is committed to this repository. The test
suite runs against fixtures/sample.motn, a small hand-written synthetic
document that reproduces the same tag shapes.
Install
python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"
Run the tests
.venv/bin/python3 -m pytest tests/ -v
Use it from Claude
Add to your MCP client config (Claude Code's .mcp.json, or the Claude
desktop app's claude_desktop_config.json):
{
"mcpServers": {
"motion": {
"command": "/absolute/path/to/motion-mcp-server/.venv/bin/python3",
"args": ["/absolute/path/to/motion-mcp-server/server.py"]
}
}
}
Typical workflow: motion_open a template → inspect with the inspect
tools → mutate with animate/structural/rig tools → motion_save_as a
new file (never overwrites the source implicitly) → motion_validate to
confirm the write round-trips → motion_open_in_motion for visual QC.
License
MIT — see LICENSE. Architecture informed by DareDev256's MIT-licensed
fcp-mcp-server; this is an
independent implementation for a different file format, not a fork.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.