Skip to main content
Glama
ulm0
by ulm0
README.md
# Ableton Live MCP

An [MCP](https://modelcontextprotocol.io) server for **Ableton Live 12**, built on the official
[Ableton Extensions SDK](https://ableton.github.io/extensions-sdk). The MCP server runs *inside*
Live as an extension — no bridge process, no MIDI remote scripts. Any MCP client (Claude Code,
Claude Desktop, Cursor, ...) connects over streamable HTTP and gets full programmatic control of
the Live Set: tracks, clips, MIDI notes, devices, parameters, mixer, scenes, warping, rendering,
and more.

```
MCP client (Claude, ...) ──streamable HTTP──▶ http://127.0.0.1:8722/mcp
                                                      │
                                     Live Extension Host (Node.js)
                                                      │
                                              Ableton Live 12
```

## Requirements

- Ableton Live 12.4.5 or newer (Extensions support)
- Node.js >= 24.14 (build only)

## Install

```bash
npm install
npm run package        # builds and produces Ableton-Live-MCP-<version>.ablx
```

Then drag the `.ablx` file onto **Settings → Extensions** in Live. The MCP endpoint starts with
Live at `http://127.0.0.1:8722/mcp` (`GET /health` for a quick check).

### Development mode

Enable **Settings → Extensions → Developer Mode** in Live, then:

```bash
npm start              # builds and runs the extension against the running Live
```

`.env` must point at your Live installation, e.g.
`EXTENSION_HOST_PATH=/Applications/Ableton Live 12 Beta.app`.

### Connect a client

Claude Code:

```bash
claude mcp add --transport http ableton-live http://127.0.0.1:8722/mcp
```

Claude Desktop (or any stdio-only client) via `mcp-remote`:

```json
{
  "mcpServers": {
    "ableton-live": {
      "command": "npx",
      "args": ["mcp-remote", "http://127.0.0.1:8722/mcp"]
    }
  }
}
```

### Configuration

The port is stored in `config.json` inside the extension's storage directory (created on first
run; the path is reported by `song_get` under `environment.storage_directory`). Default:

```json
{ "port": 8722 }
```

## How it works

- Every Live object (track, clip, device, parameter, ...) is addressed by a stable **object id**
  discovered through listing tools (`song_get`, `track_get`, `device_get`, ...).
- Ids stay valid until the object is deleted or moved, or another Live Set is loaded. Stale ids
  return an error telling the client to re-list.
- All times/positions are in **beats**; colors are `#RRGGBB`; MIDI pitches are 0–127.
- Multi-value writes (`parameter_set`) are grouped into a single undo step in Live.

## Tools

### Song
| Tool | Description |
|------|-------------|
| `song_get` | Live Set state: tempo, scale, grid, tracks, return/main tracks, scenes, cue points, environment info. The entry point — returns the object ids used everywhere else. `include` fetches only selected sections. |
| `song_set` | Set song properties (tempo). |

### Tracks
| Tool | Description |
|------|-------------|
| `track_get` | Track detail: clip slots + clips, take lanes, arrangement clips, devices, mixer with values. Address by `track_id`, `track_index`, or `track_name`; `include` selects sections. |
| `track_set` | Name / mute / solo / arm. |
| `track_create` | New audio or MIDI track. |
| `track_delete` | Delete track. |
| `track_duplicate` | Duplicate track. |
| `track_clear_clips_in_range` | Delete/truncate arrangement clips in a beat range. |
| `take_lane_create` | Add a take lane to a track. |
| `take_lane_set` | Rename a take lane. |

### Scenes & cue points
| Tool | Description |
|------|-------------|
| `scene_create` / `scene_set` / `scene_delete` / `scene_duplicate` | Manage scenes. |
| `cue_point_create` / `cue_point_set` / `cue_point_delete` | Manage arrangement locators. |

### Clips
| Tool | Description |
|------|-------------|
| `clip_create` | Create MIDI or audio clips in a session slot (by id or track + `scene_index`), arrangement track, or take lane. MIDI clips take inline `notes`; `name`/`color` apply at creation. Audio files are imported into the project automatically. |
| `clip_get` | Full clip detail (audio: warp settings + markers; MIDI: note count). |
| `clip_set` | Name, color, mute, looping, warping, warp mode. |
| `clip_delete` | Delete a session or arrangement clip. |
| `midi_clip_get_notes` | Read all MIDI notes. |
| `midi_clip_set_notes` | Write notes: `replace` all or `merge` (layer on top). |
| `midi_clip_edit_notes` | Server-side note transforms — transpose, time-shift, velocity scale/offset, quantize, delete — with pitch/time selection. No read-modify-write roundtrip. |

### Devices & racks
| Tool | Description |
|------|-------------|
| `device_get` | Device detail: parameters with ranges/value items (`parameter_filter` substring, `include_values`, `include_value_items`), rack chains (`include_chain_devices` inlines pad devices), Simpler sample. |
| `device_insert` | Insert a built-in Live device into a track or rack chain. |
| `device_delete` / `device_duplicate` | Remove or copy devices. |
| `chain_get` | Rack chain detail: devices + chain mixer. |
| `rack_insert_chain` | Add a chain to a rack. |
| `drum_chain_set` | Set the MIDI note of a drum rack pad. |
| `simpler_replace_sample` | Swap the sample in a Simpler. |

### Parameters & mixing
| Tool | Description |
|------|-------------|
| `parameter_get` | Read device/mixer parameter values (batch). |
| `parameter_set` | Write parameter values (batch, single undo step). |
| `mixer_get` | Volume / pan / sends of a track or chain, with parameter ids and unit hints. |
| `mixer_set` | Set volume / pan / sends of a track or chain in one call (single undo step). |

### Files & rendering
| Tool | Description |
|------|-------------|
| `import_file` | Copy a file into the Live project. |
| `render_track_audio` | Render pre-FX audio of an audio track to a WAV. |

### UI & commands
| Tool | Description |
|------|-------------|
| `show_dialog` | Show a modal HTML dialog inside Live (ask the user, show reports). |
| `execute_command` | Invoke Extension Host commands, e.g. `ableton-live-mcp.status`. |

## Skills

`skills/ableton-live/SKILL.md` is an installable [agent skill](https://docs.claude.com/en/docs/claude-code/skills)
that teaches an MCP client how to use these tools well (id discovery flow, beats vs. seconds,
note-editing patterns, device workflows). Install it for Claude Code with:

```bash
mkdir -p ~/.claude/skills && cp -r skills/ableton-live ~/.claude/skills/
```

Typical things you can ask a connected assistant to do:

- "Create a 4-bar house drum pattern on a new MIDI track with a Drum Rack"
- "Warp all clips on the Drums track in Complex Pro mode"
- "Turn down every track that isn't the vocal bus by 3 dB"
- "Build a song skeleton: intro, verse, chorus scenes with locators"
- "Replace the sample in Simpler with /path/to/kick.wav and map it to C1"

## Limitations

- The extension (and thus the MCP endpoint) only runs while Live is open.
- Only built-in Live devices can be inserted; third-party plug-ins can't be loaded by the SDK.
- No transport control (play/stop/record) or clip launching — the Extensions API v1.0.0 does not
  expose them. Same for browser access and parameter automation curves.
- `show_dialog` blocks until the user closes the dialog in Live.

## Tests

```bash
npm test                  # E2E against a mock Extension Host: MCP client ↔ HTTP ↔ all tools
node test/live-smoke.mjs  # against a real running Live with the extension loaded
```

The live smoke test creates its own tracks/clips/devices, verifies every tool family
(MIDI notes, warping, drum racks, rendering, ...), and deletes everything it created.

## Extension Host quirks (worth knowing)

Two behaviors of the beta Extension Host that this project works around:

1. **Bare VM context.** Extensions are evaluated in a V8 context without `global` or web
   globals (`Request`, `Response`, `ReadableStream`, `fetch`, `EventTarget`, ...), which the
   MCP SDK needs at load time. `build.ts` injects a banner that pulls them in from the main
   Node context (core-module functions are shared, so their `Function` constructor evaluates
   there). See `build.ts` for details.
2. **bigint numerics.** The host returns `bigint` for some values the SDK types as `number`
   (clip colors, note pitches, ...). `src/serialize.ts` normalizes with `num()` before
   arithmetic/JSON.
3. **Asynchronous writes.** SDK property setters (notes, names, values) return before Live
   has applied the change; a read within a few tens of ms can return the previous state.
   Agents rarely notice, but read-after-write tests must retry briefly
   (see `eventually()` in `test/live-smoke.mjs`).

Also: if the dev Extension Host crashes, Live may refuse the next control-channel handshake
("bring-up timed out") — restart Live and run `npm start` again.

## Troubleshooting

- **Endpoint not responding**: check `curl http://127.0.0.1:8722/health`. Right-click any
  track in Live — the "Ableton Live MCP: Status" context-menu action shows the endpoint the
  extension actually bound.
- **Port already in use**: if another process holds the configured port, the server logs the
  failure to `ExtensionHost.txt` and does not start. Change `port` in the extension's
  `config.json` (path shown by `song_get` under `environment.storage_directory`) — the file
  is read once at startup, so restart Live afterwards.
- **Changed config.json but nothing happened**: config is only read when the extension
  starts. Restart Live (or the dev Extension Host).

## License

MIT for the code in this repository. The `vendor/` tarballs (Ableton Extensions SDK & CLI) are
Ableton's and covered by their own license (see `sdk/LICENSE.md` in the SDK distribution).