Skip to main content
Glama
README.md
# spine-mcp

[![CI](https://github.com/UmutFarukDilli/spine-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/UmutFarukDilli/spine-mcp/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue)

**A [Model Context Protocol](https://modelcontextprotocol.io) server for
[Esoteric Software Spine](https://esotericsoftware.com) 2D skeletal animation.**
It lets an AI assistant (Claude, Cursor, …) create, edit, validate and animate Spine skeletons
without the editor running, and drives the official Spine CLI for import and export when the
editor is installed.

*Türkçe: [README.tr.md](README.tr.md)*

- **26 tools**: bones, slots, attachments (region, mesh, point, bounding box, path), skins, events,
  IK / transform / path / physics constraints, keyframes on every Spine 4.x timeline, and
  rename/delete with reference cleanup.
- **Writes exactly what the runtimes read.** Output follows `SkeletonJson` from the official
  runtimes (`value` keys, `inherit`, `drawOrder`, `light`/`dark`, absolute per-channel bezier curves,
  and the 4.3 `constraints` list or the 4.2 per-type lists depending on the file's version).
- **Checked against the official runtime.** The test suite loads generated files with
  `@esotericsoftware/spine-core` 4.3 and checks real poses (IK, constraint mixes, path positions,
  easing curves).
- **Easy curves:** pass `"ease-in-out"` or a CSS-style normalized `[cx1, cy1, cx2, cy2]`; it is
  converted to Spine's absolute bezier values and keeps its shape when keys are added later.
- **Safe edits:** every write keeps a `<file>.bak` backup and returns validation problems.
- One dependency: the official [`mcp`](https://pypi.org/project/mcp/) Python SDK (1.x and 2.x supported).

> **Unofficial project.** Spine is a trademark of Esoteric Software LLC. This project is not affiliated
> with or endorsed by Esoteric Software. You need your own [Spine license](https://esotericsoftware.com/spine-purchase)
> to use the Spine editor and CLI features.

---

## Contents

- [How it works](#how-it-works)
- [Installation](#installation)
- [Connecting to Claude and other clients](#connecting-to-claude-and-other-clients)
- [Tools](#tools)
- [Example](#example)
- [Development and tests](#development-and-tests)
- [Limitations](#limitations)

## How it works

The Spine editor's own `.spine` project files are a **binary, undocumented** format. spine-mcp edits
the documented **Spine skeleton JSON** instead, and uses the Spine CLI to move between the two:

```text
spine_create_project("hero.json")  →  add bones, slots, attachments, constraints, animations
spine_validate("hero.json")
spine_import_data(project="hero.spine", data_file="hero.json")   # a project the editor can open
spine_export(project="hero.spine", output="export/", pack=true)  # runtime JSON/binary + atlas
```

Have only a `.spine` file? Export it to JSON first (`spine_export(format="json")`). Editing tools
detect binary files and say so.

## Installation

Requires **Python 3.10+**. The Spine editor is optional (needed only for `spine_export`,
`spine_import_data` and `spine_cli_info`).

### Option A: run straight from GitHub with `uvx` (no clone)

With [uv](https://docs.astral.sh/uv/) installed, MCP clients can start the server directly:

```text
command: uvx
args:    ["--from", "git+https://github.com/UmutFarukDilli/spine-mcp", "spine-mcp"]
```

### Option B: clone and install

```bash
git clone https://github.com/UmutFarukDilli/spine-mcp.git
cd spine-mcp
python -m venv .venv
# Windows
.venv\Scripts\python -m pip install -e .
# macOS / Linux
.venv/bin/python -m pip install -e .
```

The server command is then the venv's Python with `-m spine_mcp`:

| OS | `command` |
| --- | --- |
| Windows | `C:\path\to\spine-mcp\.venv\Scripts\python.exe` |
| macOS / Linux | `/path/to/spine-mcp/.venv/bin/python` |

Installing the package (`pip install -e .`) matters: MCP clients start the server from another working
directory, so `python -m spine_mcp` must work from anywhere. Check with:

```bash
/path/to/spine-mcp/.venv/bin/python -c "import spine_mcp; print(spine_mcp.__version__)"
```

### Spine CLI (optional)

The server finds the editor's CLI automatically (`Spine.com` / `SpineTrial.com` on Windows,
`Spine.app` on macOS, `Spine.sh` on Linux, or anything on `PATH`). Point it at a specific install with
the `SPINE_CLI_PATH` environment variable. Run the `spine_doctor` tool to see what it found.

## Connecting to Claude and other clients

All clients use the same three values; examples below use Option B on Windows. Adjust the paths
(or use the `uvx` command from Option A).

```json
{
  "mcpServers": {
    "spine": {
      "command": "C:\\path\\to\\spine-mcp\\.venv\\Scripts\\python.exe",
      "args": ["-m", "spine_mcp"],
      "env": { "SPINE_CLI_PATH": "C:\\Program Files\\Spine\\Spine.com" }
    }
  }
}
```

`env` is optional.

### Claude Code (CLI, or the Code tab of the Claude desktop app)

```bash
claude mcp add spine --scope user -- /path/to/spine-mcp/.venv/bin/python -m spine_mcp
# with a Spine CLI path:
claude mcp add spine --scope user -e SPINE_CLI_PATH="/Applications/Spine.app/Contents/MacOS/Spine" -- /path/to/spine-mcp/.venv/bin/python -m spine_mcp
```

Without the CLI, add the `"spine"` entry to `mcpServers` in `~/.claude.json` (user scope, with
`"type": "stdio"`), or to a project's `.mcp.json` to share it with that project.

### Claude Desktop (chat)

Settings → Developer → **Edit Config** opens `claude_desktop_config.json`. Add the `mcpServers` block
above at the top level, leaving the other settings as they are. Usual locations:

| OS | File |
| --- | --- |
| Windows | `%APPDATA%\Claude\claude_desktop_config.json` (Microsoft Store build: `%LOCALAPPDATA%\Claude-Data\claude_<id>\claude_desktop_config.json`) |
| macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |

### Cursor and others

Cursor reads the same block from `.cursor/mcp.json`. Any other MCP client: use the command, args and
env above (stdio transport).

### After adding it

Config is read at startup: quit the app completely and reopen it (start a new session in Claude Code).
Then ask, for example, *"run spine_doctor"*.

| Problem | Fix |
| --- | --- |
| Tools do not show up | Restart the app fully; check the JSON for missing commas or unescaped `\` |
| `No module named 'spine_mcp'` | Run `pip install -e .` with the venv's Python |
| Test the server by hand | Run the command yourself; it should wait silently for input (Ctrl+C to quit) |

## Tools

### Discovery and validation

| Tool | Description |
| --- | --- |
| `spine_doctor` | Python/MCP versions, detected Spine CLIs and their versions, hints |
| `spine_list_projects` | Binary `.spine` projects and Spine JSON files under a folder (version and counts) |
| `spine_inspect` | Version, bone tree, slots, skins, constraints, animations, events |
| `spine_validate` | Errors and warnings: duplicate names, missing parents, broken attachments and meshes, timelines with unknown targets, unsorted keys, out-of-range curves, fields the runtime ignores, 4.2/4.3 constraint layout |

### Creating

| Tool | Description |
| --- | --- |
| `spine_create_project` | New Spine 4.x skeleton JSON with a `root` bone |
| `spine_add_bone` | Bone (parent, length, x/y, rotation, scale, shear, `inherit`) |
| `spine_add_slot` | Slot (bone, setup attachment, color, dark color, blend, draw-order index) |
| `spine_add_attachment` | `region`, `mesh` (grid with hull), `point`, `boundingbox`, `path` (smooth curve through anchor points) |
| `spine_add_skin` | Skin (outfit/variant), optionally copied from another skin |
| `spine_add_event` | Event with int/float/string/audio/volume/balance |

### Constraints

Written in the file's format: the 4.3 typed `constraints` list (order = list position) or the 4.2
`ik` / `transform` / `path` / `physics` lists (with `order`).

| Tool | Description |
| --- | --- |
| `spine_add_ik_constraint` | 1- or 2-bone IK (mix, bend direction, softness, stretch, compress) |
| `spine_add_transform_constraint` | Bones copy a source bone's rotate/x/y/scaleX/scaleY/shearY with per-property mix and offset, `local`, `additive`; on 4.3, `mapping` links different properties (e.g. source rotation → target x) |
| `spine_add_path_constraint` | Places bones along a `path` attachment (position/spacing/rotate modes, mixes) |
| `spine_add_physics_constraint` | Spring physics for hair, tails and cloth (x/y/rotate/scaleX/shearX response, inertia, strength, damping, mass, wind, gravity) |

### Animating

| Tool | Description |
| --- | --- |
| `spine_add_animation` | Empty animation |
| `spine_set_keyframes` | Keys for `rotate`, `translate`, `translatex/y`, `scale`, `scalex/y`, `shear`, `shearx/y`, `inherit`, `attachment`, `rgba`, `rgb`, `rgba2`, `rgb2`, `alpha`, `event`, `drawOrder`, `ik`, `transform`, `path.position/spacing/mix`, `physics.inertia/strength/damping/mass/wind/gravity/mix/reset` |
| `spine_delete_keyframes` | Remove keys at given times, or a whole timeline |
| `spine_duplicate_animation` | Copy an animation (e.g. `walk` → `walk-fast`) |
| `spine_delete_animation` | Remove an animation |

Curve presets: `linear`, `stepped`, `ease`, `ease-in`, `ease-out`, `ease-in-out`, `smooth`, or a
normalized `[cx1, cy1, cx2, cy2]`. In `transform` and `path.mix` keys, mixes you leave out keep the
constraint's setup value (runtimes would otherwise treat them as 1 and switch on unused properties).

### Fixing

| Tool | Description |
| --- | --- |
| `spine_update_bone` | Change the setup pose; `new_name` renames everywhere, `parent` moves the subtree (cycles are refused) |
| `spine_update_slot` | Bone, attachment, colors, blend, draw-order position, `new_name` |
| `spine_delete` | Delete a bone (`cascade`), slot, attachment, event, constraint, animation or skin, and clean up references |
| `spine_upgrade` | Convert files written by spine-mcp 0.1 to correct 4.x fields (editing tools do this automatically) |

### Spine CLI (editor required)

| Tool | Description |
| --- | --- |
| `spine_export` | JSON or binary export, optional atlas packing, animation clean-up, `dry_run` |
| `spine_import_data` | Import JSON/binary skeleton data into a `.spine` project |
| `spine_cli_info` | `Spine -i project` output (editor version, warnings) |

## Example

A conversation like *"make a character with a waving arm"* turns into calls such as:

```text
spine_create_project(project="hero.json", name="hero", width=512, height=512)
spine_add_bone(project="hero.json", name="hip", parent="root", y=120)
spine_add_bone(project="hero.json", name="torso", parent="hip", length=80, rotation=90)
spine_add_slot(project="hero.json", name="torso", bone="torso")
spine_add_attachment(project="hero.json", slot="torso", name="torso", kind="region", width=64, height=120)
spine_set_keyframes(project="hero.json", animation="idle", timeline="rotate", target="torso",
                    curve="ease-in-out",
                    keys=[{"time": 0, "value": 0}, {"time": 1, "value": 8}, {"time": 2, "value": 0}])
spine_validate(project="hero.json")
```

`examples/demo.json` is a complete character (13 bones, 10 slots, `idle` / `walk` / `wave` animations,
events, placeholder images in `examples/images/`), built by `examples/make_demo.py` (needs Pillow).

## Development and tests

```bash
pip install -e ".[test]"
pytest
```

- `tests/test_project.py`: the document model (curves, constraints, upgrade, rename/delete)
- `tests/test_validation.py`: validation rules
- `tests/test_cli.py`: CLI detection and command building
- `tests/test_stdio.py`: end-to-end MCP calls over real stdio JSON-RPC
- `tests/test_runtime.py`: loads and poses generated files with the official Spine runtime
  (needs Node.js 18+ and `npm ci` in `tools/`; skipped otherwise)

```bash
cd tools && npm ci && cd ..
node tools/verify_runtime.mjs examples/demo.json                          # load + play every animation
node tools/sample_pose.mjs examples/demo.json walk 0,0.5 leg-front,hip    # bone world values
```

CI runs the suite on Windows, macOS and Linux with Python 3.10 and 3.13, plus `mcp<2`.
See [CONTRIBUTING.md](CONTRIBUTING.md).

`@esotericsoftware/spine-core` is only a development dependency for these checks; it is not bundled
with or required by the server. It is covered by the
[Spine Runtimes License](https://esotericsoftware.com/spine-runtimes-license).

## Limitations

- **No editor GUI automation.** The Spine CLI only exports, imports, packs and reports info;
  spine-mcp adds JSON editing on top of it.
- Binary `.spine` projects cannot be edited directly (see [How it works](#how-it-works)).
  Spine 3.x JSON is refused for editing; `spine_validate` warns about it.
- 4.3 `slider` constraints are read and validated, but no tool creates them yet.
- The 4.2 constraint layout was checked by hand with `spine-core` 4.2; automated runtime tests use 4.3.
- CLI features need a licensed Spine editor. The Spine **Trial** does not export, so
  `spine_export` times out with it; the generated command can be checked with `dry_run=true`.
- Mesh attachments are generated as regular grids; pass `uvs` / `vertices` / `triangles` / `hull`
  for custom meshes, or refine them in the editor.
- CLI exports must match your runtime version (a Spine rule).

## License

[MIT](LICENSE)