Figma Motion MCP
# Figma Motion MCP
Claude Code → **MCP** → our Figma plugin → **Figma Plugin API**. Authors Figma Motion
(keyframes / animation styles) programmatically from a prompt. No Figma agent, no `use_figma`.
```
Claude Code ──stdio(JSON-RPC)── MCP server ──ws://localhost:3055── plugin ui.html ──postMessage── plugin main thread ── figma.* (Motion API, Beta)
```
The MCP server process also hosts the WebSocket bridge, so there is no separate relay.
## What it can do
| MCP tool | Plugin command | Purpose |
| ----------------------------- | ----------------------- | ---------------------------------------------------- |
| `get_selection` | `get_selection` | selected node id/name/type |
| `probe` | `probe` | confirm Motion (Beta) API is exposed in your build |
| `read_motion` | `read_motion` | current timelines / animated props / tracks / styles |
| `list_motion_templates` | (server local) | built-in code templates |
| `apply_motion_template` | `apply_tracks` | resolve template+params → apply keyframe tracks |
| `apply_keyframes` | `apply_tracks` | raw keyframe tracks |
| `set_timeline_duration` | `set_timeline_duration` | timeline length (s) |
| `remove_motion` | `remove_motion` | **delete** tracks and/or applied styles |
| `list_figma_animation_styles` | `list_animation_styles` | native preset styles |
| `apply_animation_style` | `apply_animation_style` | apply a native preset |
Create / modify / delete are all covered. Template resolution runs **server-side** — the
plugin only ever receives concrete tracks, so it stays dumb and templates are versioned here.
## Setup (teammates: one command)
The folder is self-contained (no monorepo deps). Hand someone this folder, they run:
```bash
cd figma-motion-mcp
./setup.sh
```
`setup.sh` does `npm install`, resolves your absolute node path (nvm-safe), and registers
the MCP server `figma-motion` at **local scope** (this project only, not committed — so
each teammate registers their own; no shared/hardcoded paths). It prints the remaining
manual steps.
### Manual equivalent (if you prefer / no `claude` CLI)
```bash
npm install
claude mcp add figma-motion -- "$(command -v node)" "$(pwd)/server/mcp-server.js"
claude mcp get figma-motion # verify
```
> nvm users: the absolute node path matters — the MCP subprocess won't inherit your shell PATH.
> `setup.sh` / the `$(command -v node)` form handles this automatically.
### Then: run the plugin in Figma
Figma desktop → **Plugins → Development → Import plugin from manifest…** → pick
`figma-motion-mcp/plugin/manifest.json`. Open a NEW Claude session (it auto-starts the
server + WS bridge); the panel should turn green **"Connected — bridge ready"**.
## First run — runtime probe (do this once)
Typings (`@figma/plugin-typings@1.130.0`) confirm the Motion API contract, but it is **Beta**
and gated per build/seat. Before relying on it:
1. In Figma, select any node, then run the plugin.
2. In Claude: _"run probe"_.
3. Confirm `applyManualKeyframeTrack: "function"` and `figma.motion` is non-null.
4. `animatedProperties` shows the real field names for your build — if any template name
mismatches, fix it in `server/templates.js`.
If `applyManualKeyframeTrack` is `"undefined"`, Motion is not enabled in your Figma build yet.
## Example flow
```
1) Select a frame/layer in Figma.
2) "get_selection" → nodeId
3) "apply fadeInUp to <nodeId>, duration 0.5" → apply_motion_template
4) "read_motion <nodeId>" → timelines / animatedProperties
5) "nudge TRANSLATION_Y keyframe to 32→0" → apply_keyframes
6) "remove OPACITY motion from <nodeId>" → remove_motion
```
## Notes / limits
- **Motion API is Beta** — signatures may change. Write calls are wrapped; typings pinned to 1.130.0.
- **No native style publishing** (apply-only). Reuse lives in `server/templates.js`.
- **Single-client MVP** — newest plugin connection wins.
- **No `SCALE`** field — use `SCALE_XY` (corrected vs the original draft spec).
- **stdout is JSON-RPC only** — all server logs go to stderr.
- Override the bridge port with `FIGMA_MOTION_WS_PORT` (default 3055; update `ui.html` URL to match).
TDQS
Scored across 10 tools
Each tool has a clearly distinct purpose: applying motion via different methods (style, keyframes, template), reading, removing, setting duration, listing available assets, getting selection, and probing API. No two tools overlap in functionality.
All tool names follow a consistent verb_noun pattern in snake_case (e.g., apply_animation_style, list_motion_templates). Verbs are predictable and clearly indicate the action.
With 10 tools, the set is well-scoped for a motion server. Each tool covers a necessary aspect of the motion workflow without redundancy or excess.
The tools provide comprehensive coverage for applying, reading, removing, and configuring motion, plus listing available styles/templates. A minor gap is the lack of a tool to explicitly update an existing animation, but remove+reapply works around it.