Skip to main content
Glama
README.md
# ableton-mcp-loopback

A loopback-bound [Model Context Protocol](https://modelcontextprotocol.io) (MCP)
server for Ableton Live. It lets an MCP client (Claude, an agent, an LLM tool
runner) drive Ableton Live — set tempo, create tracks and clips, add MIDI notes,
start/stop playback — over the standard MCP stdio transport.

This is a security-fix fork of
[`ahujasid/ableton-mcp`](https://github.com/ahujasid/ableton-mcp) (MIT). **The
one material change is the network bind:** the upstream Remote Script binds its
control socket to `0.0.0.0` (every network interface), exposing unauthenticated
Ableton control to the LAN. This fork binds **`127.0.0.1` (loopback) as a hard
constant** — the kernel refuses any non-loopback peer at the socket layer, with
no firewall rule required. See [Security](#security) below.

## Why two parts

Ableton's Live Object Model (LOM) is reachable **only** from a MIDI Remote
Script loaded into Live's embedded Python — there is no out-of-process LOM API.
So the project is irreducibly two pieces:

1. **`RemoteScript/`** — a MIDI Remote Script that runs *inside* Ableton Live. It
   opens a small loopback TCP socket (`127.0.0.1:9877`) and translates incoming
   JSON commands into LOM calls (mutating calls run on Live's main thread).
2. **`ableton_mcp_loopback/`** — the stdio MCP server. It runs as a normal
   process, connects to `127.0.0.1:9877` as a *client*, and relays MCP tool
   calls to the Remote Script.

```
MCP client  <—stdio—>  ableton-mcp-loopback server  <—TCP 127.0.0.1:9877—>  Remote Script (in Live)  —>  LOM
```

## Setup

### 1. Install the MCP server

With [uv](https://docs.astral.sh/uv/) (recommended — no manual venv):

```bash
uvx --from git+https://github.com/applicate2628/ableton-mcp-loopback ableton-mcp-loopback
```

Or with pip:

```bash
pip install git+https://github.com/applicate2628/ableton-mcp-loopback
ableton-mcp-loopback
```

Then point your MCP client at the `ableton-mcp-loopback` command (stdio). For
example, in an MCP client config:

```json
{
  "mcpServers": {
    "ableton": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/applicate2628/ableton-mcp-loopback", "ableton-mcp-loopback"]
    }
  }
}
```

### 2. Install the Remote Script into Ableton Live

This is the one irreducible manual Ableton step — the LOM is only reachable from
a Control Surface script loaded by Live itself.

1. Copy the `RemoteScript/` folder into Ableton's **MIDI Remote Scripts**
   directory, renaming it to a clear name such as `ableton_mcp_loopback`:

   - **Windows:** `C:\ProgramData\Ableton\Live <version>\Resources\MIDI Remote Scripts\`
     or `\Users\<you>\Documents\Ableton\User Library\Remote Scripts\`
   - **macOS:** `/Applications/Ableton Live <version>.app/Contents/App-Resources/MIDI Remote Scripts/`
     or `~/Music/Ableton/User Library/Remote Scripts/`

   The result should be a folder like `.../MIDI Remote Scripts/ableton_mcp_loopback/`
   containing `__init__.py`.

2. Start (or restart) Ableton Live.

3. Open **Preferences → Link / Tempo / MIDI** (the **MIDI** tab), and under
   **Control Surface** select **`ableton_mcp_loopback`** (the folder name you
   used). Leave Input/Output set to *None*. Live then loads the script and you
   should see `ableton-mcp-loopback: Listening on 127.0.0.1:9877` flash in Live's
   status bar.

That's it — the MCP server will connect to the Remote Script automatically. If
the server starts before the Control Surface is loaded, it retries the
connection.

## Tools

This release ships the **full upstream `ahujasid/ableton-mcp` tool surface** — it
is a drop-in replacement minus the upstream wide-bind network exposure and minus
telemetry. All 21 tools are present:

| Tool | What it does |
|---|---|
| `get_session_info` | Tempo, time signature, track counts, transport state |
| `get_track_info` | A track's clip slots, devices, mixer state |
| `set_tempo` | Set session BPM |
| `start_playback` | Start the session transport |
| `stop_playback` | Stop the session transport |
| `create_midi_track` | Add a MIDI track |
| `set_track_name` | Rename a track |
| `create_clip` | Create an empty MIDI clip in a slot |
| `create_audio_clip` | Import an audio file into an audio clip slot (Live 12.0.5+) |
| `add_notes_to_clip` | Write MIDI notes into a clip |
| `set_clip_name` | Rename a clip |
| `fire_clip` | Launch a clip |
| `stop_clip` | Stop a clip |
| `load_instrument_or_effect` | Load a device onto a track by browser URI |
| `load_drum_kit` | Load a drum rack and a drum kit into it |
| `get_browser_tree` | List the browser's category tree |
| `get_browser_items_at_path` | List browser items at a category path |
| `switch_to_arrangement_view` | Switch Live's window to the Arrangement view |
| `set_arrangement_time` | Move the arrangement playhead (beats) |
| `get_arrangement_clips` | List a track's Arrangement-timeline clips |
| `duplicate_to_arrangement` | Copy a Session clip into the Arrangement |

A typical end-to-end flow: `create_midi_track` → `set_track_name` →
`create_clip` → `add_notes_to_clip` → `fire_clip`.

### Input validation and message framing

Every command's parameters are validated **before** any Live Object Model call
runs (indices are non-negative integers, tempo is within Live's range, MIDI
pitch/velocity are 0–127, durations are positive and finite, note lists are
well-formed). An invalid value returns a structured `status: error` response and
never reaches Live.

The TCP link between the server and the Remote Script uses **newline-delimited
JSON framing**: each message is one JSON object terminated by a single `\n`. Both
ends buffer with a bounded receive buffer, parse each complete frame, reject a
malformed frame without poisoning the stream, and handle multiple frames in one
packet. **The wire protocol changed in this release** — if you are upgrading from
the earlier P1 build, you must reload the Remote Script in Live (re-select the
Control Surface, or restart Live) so both ends speak the same framing.

## Security

**Loopback by construction, not by firewall convention.**

The Remote Script binds its socket with `HOST = "127.0.0.1"` as a **hard
constant**. There is no operator override, no bind-address config key, and no
environment variable that can widen it. Because the socket is bound to the
loopback interface, the operating-system kernel never associates it with the
host's LAN/routable interface, so a connection from any non-loopback address is
**refused at the socket layer** — you do not need a firewall rule for this, and
no firewall misconfiguration can undo it.

Contrast with upstream `ahujasid/ableton-mcp`, which binds `0.0.0.0` — that
accepts connections from *any* interface, meaning any device on the same LAN can
issue unauthenticated commands to Ableton. That is the exposure this fork
removes.

This build also contains **no telemetry** — the upstream telemetry module, the
`user_prompt` capture parameter, and the analytics dependency are all removed
(not merely disabled).

**Residual risk (local processes).** Any process running on the *same machine*
can still reach `127.0.0.1:9877`. This is the same trust posture as every local
stdio MCP server and every local development service. The loopback bind protects
against remote/LAN attackers, not against other local processes on a machine you
already trust. Finer per-tool consent is out of scope for this component.

## License

MIT. See [LICENSE](LICENSE). Forked from `ahujasid/ableton-mcp` (MIT,
copyright (c) 2025 Siddharth Ahuja); the upstream copyright is preserved in
`LICENSE`.

## Development

```bash
pip install -e .[test]
pytest                       # security probe + tool-surface tests (no Ableton needed)
python -m ableton_mcp_loopback.server   # run the server (will retry to reach Live)
```

The tests under `tests/` are all runnable **without** Ableton: they assert the
loopback bind constant, scan the tree for any wide-bind literal, exercise a real
loopback socket to prove a non-loopback connect is refused (plus an always-run
structural guard that the bind is loopback, so the security check can never go
green on a skip), check full upstream tool-surface parity on both the server and
the Remote Script, exercise the newline-delimited message framing (partial /
multi-frame / malformed / oversized handling), and exercise the parameter
validation. The full LOM smoke (create track → notes → fire → audible) requires a
live Ableton Live and is run separately.

TDQS

A3.7/5.0

Scored across 21 tools

Disambiguation5/5

Each tool has a clearly distinct purpose, from track/clip creation to playback and arrangement management. No overlapping or ambiguous tools.

Naming Consistency4/5

Most tools follow a verb_noun pattern (e.g., create_midi_track, set_tempo). Minor deviations like duplicate_to_arrangement and switch_to_arrangement_view are still clear and predictable.

Tool Count5/5

21 tools cover the essential operations for Ableton Live session control without being excessive or sparse. Each tool adds value.

Completeness4/5

The surface covers core workflows (create, edit, play, browse) but lacks delete/remove operations for tracks or clips, which is a minor gap.

Maintenance

ActivityStale
ResponsivenessNo issues