ableton-mcp-loopback
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