Skip to main content
Glama
giuliobracci

ableton-mcp-server

by giuliobracci
README.md
# ableton-mcp-server

An [MCP](https://modelcontextprotocol.io) server that exposes **Ableton Live** to
AI agents, built as a native **Ableton Extension** on top of the official
[`@ableton-extensions/sdk`](https://ableton.github.io/extensions-sdk) (released
in beta, June 2025).

It lets an agent (Claude, etc.) **read and edit a Live set** — tracks, clips,
MIDI notes, devices/parameters, scenes — and render/import audio, all over a
local MCP endpoint.

> Status: beta. Targets Extensions SDK API `1.0.0`.

## How it works

An Ableton Extension is an `activate(context)` function that runs **inside Live's
Extension Host** — a full Node.js ≥22 process embedded in Live. This project's
`activate()` initializes the SDK and starts an **in-process MCP server over
Streamable HTTP**, bound to `127.0.0.1`. The tool handlers call straight into
Live's data model — no second process, no IPC.

```
┌─────────────── Ableton Live ───────────────┐
│  Extension Host (Node 22)                   │
│   activate() ─ initialize(sdk) ─ Live data  │
│        │                                    │
│   MCP server  ── Streamable HTTP ──┐        │
└────────────────────────────────────┼───────┘
                                      │ 127.0.0.1:39001/mcp
                          ┌───────────▼──────────┐
                          │  MCP client (Claude) │
                          └──────────────────────┘
```

Two consequences shape the design:

- **stdio is owned by the host**, so the MCP transport is HTTP, not stdio.
- **The lifecycle is inverted** — Live owns the process — so the MCP client
  *connects to* an already-running endpoint rather than spawning it. The server
  is only alive while Live + the extension are running; clients must tolerate it
  appearing/disappearing.

## Object addressing

Tools reference Live objects by stable path strings:

| Address | Object |
|---|---|
| `song` | the song |
| `track/0` | first regular track |
| `track/0/clipslot/3` | a session clip slot |
| `track/0/clipslot/3/clip` | the clip in that slot |
| `track/0/arrangement-clip/0` | an arrangement clip |
| `track/0/device/1` | a device on a track |
| `track/0/device/1/parameter/5` | a device parameter |
| `scene/2` | a scene |

## Tools (31)

| Group | Tools |
|---|---|
| **Song** | `get_song_state`, `set_tempo` |
| **Tracks** | `list_tracks`, `get_track`, `create_midi_track`, `create_audio_track`, `duplicate_track`, `delete_track`, `rename_track`, `set_track_state` |
| **Clips** | `list_clip_slots`, `get_clip`, `create_midi_clip`, `create_arrangement_clip`, `create_audio_clip`, `delete_clip`, `set_clip_properties` |
| **MIDI** | `get_notes`, `set_notes` |
| **Devices** | `list_devices`, `insert_device`, `delete_device`, `list_parameters`, `get_parameter`, `set_parameter` |
| **Scenes** | `list_scenes`, `create_scene`, `delete_scene`, `rename_scene` |
| **Resources** | `render_pre_fx_audio`, `import_into_project` |

### What an agent can do
Read the set's state; compose (create tracks/clips, **write MIDI notes**),
edit (rename, mute/solo/arm, clip name/color/loop on-off), sound-design (insert
devices, set parameter values), and render/import audio (e.g. render a range of
an audio track to WAV).

### Known limits (from the SDK, not this server)
- **No transport/playback**: no play/stop/fire/record — the agent composes and
  edits, it doesn't perform.
- **Loop points are read-only** after creation (`set_clip_properties` only
  toggles `looping`).
- **No push events**: request/response only; poll to observe changes.
- `render_pre_fx_audio` renders *pre-effects* audio of an **arrangement** range.

## Setup

Requires Node ≥22.11 and a version of Ableton Live that supports extensions.

```bash
npm install
npm test          # unit + real HTTP-loopback tests (no Live needed)
npm run build     # bundles src/extension.ts -> dist/extension.js (CJS)
```

### Run inside Live (development)

You need the **Live Beta build that supports extensions** (from Ableton's
Centercode release page). Ableton recommends Node ≥ 24.14.1 for the toolchain;
this project also builds/tests fine on Node 22 (Live runs the extension on its
own bundled Node).

1. **Enable Developer Mode** in Live: `Preferences → Extensions → Developer
   Mode`. Required — otherwise the CLI can't connect to Live.
2. **Point the CLI at Live**, either by copying `.env.example` to `.env` and
   setting `EXTENSION_HOST_PATH`, or by passing `--live`:

   ```bash
   npm start                                   # uses .env
   # or
   npm start -- --live "/Applications/Ableton Live 12 Suite Beta.app"
   ```

`npm start` builds the extension and launches Live's Extension Host with it. On
start you'll see, in the terminal/host log:

```
[ableton-mcp] MCP server listening on http://127.0.0.1:39001/mcp
```

Config via env: `ABLETON_MCP_HOST` (default `127.0.0.1`), `ABLETON_MCP_PORT`
(default `39001`). Pass `--inspect` for VS Code debugging.

### Connect an MCP client

Because the server is already running, register it as an **HTTP** MCP server (do
not let the client spawn it). For Claude Code:

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

Or inspect it with the MCP Inspector:

```bash
npx @modelcontextprotocol/inspector
# transport: Streamable HTTP, URL: http://127.0.0.1:39001/mcp
```

Then try: `get_song_state`, `set_tempo {bpm:124}`, `create_midi_track`,
`create_midi_clip {track:"track/0", slot:0, length:4}`,
`set_notes {clip:"track/0/clipslot/0/clip", notes:[{pitch:60,startTime:0,duration:1}]}`.

### Package for distribution

```bash
npm run package   # production bundle -> Ableton-MCP-0.1.0.ablx (manifest + entry)
```

A `.ablx` is the shareable/installable archive. During the SDK beta the primary
way to load an extension is Developer Mode + `npm start` above.

## Development

Built test-first with [vitest](https://vitest.dev). The architecture keeps the
host out of the test path:

- **Pure logic** (`addressing.ts`, `notes.ts`) — tested with no mocks.
- **Tools** depend only on the narrow `Live` interface and are tested against
  an in-memory `FakeLive`.
- **MCP server** is tested with a real `Client`+`McpServer` over
  `InMemoryTransport`, and the HTTP layer with a **real loopback** (real MCP
  client over `StreamableHTTPClientTransport`).
- The only host-bound code (`live.context.ts`, `extension.ts`) is covered by the
  real-Live integration test, not unit tests — the native host can't run in CI.

```
src/
  addressing.ts      object path parse/serialize (pure)
  notes.ts           MIDI note validation (pure)
  live.ts            the Live facade interface + DTOs
  live.fake.ts       in-memory Live for tests
  live.context.ts    real Live over the Extension Host
  tools/             one file per tool group + registry
  server.ts          builds the McpServer from the tool registry
  http.ts            Streamable HTTP transport on localhost
  extension.ts       activate() entry point
```

## License

The Ableton Extensions SDK and CLI are © Ableton AG (see their `LICENSE.md`).
This project is provided as-is.