Skip to main content
Glama
README.md
# 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

A3.7/5.0

Scored across 10 tools

Disambiguation5/5

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.

Naming Consistency5/5

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.

Tool Count5/5

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.

Completeness4/5

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.

Maintenance

ActivityStale
ResponsivenessNo issues