Skip to content
Back to skills

Ableton Mcp

ASecurity

Use when controlling Ableton Live through the AbletonMCP server — tracks, clips, scenes, MIDI notes, instruments and effects, device parameters, mixing, automation, tempo or time signature — or when the Live connection or a tool call fails.

  • 3 stars
  • 0 votes
  • 0 copies
  • 5 views
  • Added September 5, 2026
ai-agentspythongoawstestingapi

Works with

  • claude code
  • cli
  • api
  • mcp

Security analysis

A100/100

Pro scans all 3 files and shows the line behind each finding

Scanned October 6, 2026

npx -y skills add PerIPan/music-workflow-skills --skill ableton-mcp --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Ableton Mcp?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Ableton Mcp
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/peripan-ableton-mcp/badge)](https://www.skillsdirectory.com/skills/peripan-ableton-mcp)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: ableton-mcp
description: Use when controlling Ableton Live through the AbletonMCP server — tracks, clips, scenes, MIDI notes, instruments and effects, device parameters, mixing, automation, tempo or time signature — or when the Live connection or a tool call fails.
---

# Ableton Live via MCP

Claude drives a live Ableton Set through the AbletonMCP server (jpoindexter fork v2.0.0,
128 tools, all prefixed `mcp__ableton__`). Limits below are for this fork.

**References (read on demand):**
- `references/setup-install.md` — first-time install (Remote Script + server + verify)
- `references/troubleshooting.md` — connection failures, tool errors
- `references/als-xml.md` — reading Arrangement content from the saved `.als` (MCP can't)
- `references/remote-script-patch.md` — the local patch that adds audio-file loading and
  working warp commands (`ableton-song-remix` needs it)

For arrangement *craft* (section design, bass/drum patterns, FX chains) use the
`ableton-arrangement` skill; this skill is the mechanics and the gotchas.

## Mental model

- **Live and stateful.** Every call mutates the open Set immediately. No preview/dry-run.
  Undo is Live's own Cmd/Ctrl-Z.
- **Single session.** Controls one Ableton instance — the frontmost open Set. No diffing
  two Sets, no background operation. Two clients on one Live collide; work sequentially.
- **No autosave.** Claude can't save/open/new a Set — the USER Cmd-S's. After a Set
  switch, the server re-attaches to the new frontmost Set.
- **Deferred tools (Claude Code).** Load schemas before first use:
  `ToolSearch select:mcp__ableton__<name>`.
- **Reason in BARS, never seconds.** Sizes and positions are bar counts; convert
  everything to bars up front.

## Tool map

| Area | Representative tools |
|---|---|
| Transport | start/stop_playback, start/stop_recording, set_tempo, set_metronome, jump_to_time, capture_midi |
| Tracks | create_midi/audio/group_track, set_track_name/volume/pan/mute/solo/arm/color, set_track_input/output_routing, delete/duplicate_track, freeze/flatten |
| Clips | create/delete/duplicate/fire/stop_clip, set_clip_name/color/loop/gain/pitch, get_clip_notes |
| MIDI notes | add_notes_to_clip, remove_notes (range), remove_all_notes, transpose_notes, quantize_clip_notes, humanize_clip_timing/velocity |
| Devices / FX | search_browser, load_instrument_or_effect, get/set_device_parameter, toggle/delete_device, move_device_left/right, get_rack_chains |
| Scenes | create/delete/duplicate/fire_scene, set_scene_name/color, get_all_scenes |
| Mixing | set_send_level, get/set_return_volume/pan, set_master_volume/pan |
| Automation | get/set/clear_clip_automation, toggle_session_record, set_overdub |
| AI helpers | get_scale_notes, generate_drum_pattern, generate_bassline |

Most tools take `(track_index, clip_index)` — both **0-based** (Live's UI is 1-based:
"track 3" in the UI = index 2).

## Capabilities vs hard limits (all observed in testing)

**Reachable:** Session-view clip CRUD + MIDI editing, track/scene CRUD, device loading +
any device parameter on regular tracks, transport, mixing/sends, clip automation,
humanize, generative helpers.

**Not reachable — plan around:**
- ❌ Effects on the **Master track** — user adds limiter/EQ manually.
- ❌ **Stamping clips into Arrangement** — only real-time recording reaches Arrangement
  (and session-fire→arrangement-record produced an empty arrangement). Bounce loops via
  **Resample** into a session audio clip, or drag manually.
- ❌ **Firing an empty slot to record** — "click empty slot to record" is UI-only.
- ❌ **Render/export audio** — user does File → Export.
- ❌ **Return-track device parameters** — rejected ("Track index out of range"). Use
  set_return_volume/pan, or move the FX to a regular track.
- ⚠️ **Per-clip mute** — no clean toggle; `set_clip_gain` 0 (reversible) or UI Deactivate.
- ⚠️ **Follow Actions** unreachable — use launch quantization for count-ins/progressions.
- ⚠️ **`set_clip_automation` "Volume"** works on simple instrument tracks; rack-based
  tracks (drum racks, amp racks) often reject it → fall back to per-note velocity or a
  Utility device.
- ⚠️ **No visual feedback** — no screenshot tool. Workaround: macOS `screencapture` +
  Read the PNG.

## Hard rules (gotchas that bite)

1. **Load with `load_instrument_or_effect`**, not `load_item_to_track` (errors "Unknown
   command"). URIs are HTML-encoded: `query:AudioFx#EQ%20Eight`.
   ⚠️ **Its success message lies about the device list** — it returns
   `"Loaded instrument ... Devices on track:"` with the list *empty* even when the load
   worked. Don't retry on the strength of that; confirm with `get_track_info(track_index)`
   and read the `devices` array.
2. **Instruments/presets live under the `sounds` browser category**, not `instruments`
   (returns nothing). Pianos: `query:Sounds#Piano & Keys`; guitars:
   `query:Sounds#Guitar & Plucked`. Use `search_browser(query, category="sounds")`.
   Search matches **literal preset names**, so instrument nicknames miss: `"Rhodes"`
   returns nothing, `"Electric Piano"` finds *Electric Piano Daze*. Search the generic
   name, not the iconic one.
3. **Chunk note pushes ≤140 notes** per `add_notes_to_clip` MCP call (larger has failed
   silently). **Never two pushes to the same clip in one parallel batch** — they race.
   Sequential per clip; parallelize only across different clips. For hundreds of notes use
   the raw-TCP bulk path below (300 per chunk works there).
4. **Reading a big clip can exceed the response token limit.** Generate notes in a
   script → save JSON → push from that. Don't round-trip 500 notes through a read.
5. **`remove_notes(from_time, time_span, from_pitch, pitch_span)` for surgical edits** —
   prefer over `remove_all_notes`. **Always assume the user hand-edited the clip** —
   read or remove-by-range rather than wiping. **`remove_all_notes` only clears 0 → clip
   length**: notes at negative times or past the end survive. To truly clear a clip:
   `remove_all_notes`, then `remove_notes(from_time=-16, time_span=16 + length + 16)`,
   then confirm with `get_clip_notes`.
6. **Effects load at the END of the chain.** Build in order or reorder with
   `move_device_left/right`.
7. **EQ Eight freq is normalized 0–1:** `value = log10(freq/20) / 3` (1 kHz ≈ 0.566,
   250 Hz ≈ 0.366, 130 Hz ≈ 0.271). Band N (A-set) param indices: On `4+(N-1)*10`, Type
   `5+…`, Freq `6+…`, Gain `7+…`, Q `8+…`. Filter types: 0=HP48 1=HP12 2=LowShelf 3=Bell
   4=Notch 5=HighShelf 6=LP12 7=LP48.
8. **Distortion:** `Overdrive` — Drive/Tone/Dry-Wet on 0–100. `Saturator` —
   Drive/Output/Dry-Wet on 0–1, Type 0–7 (hard curve = fuzz). `Pedal`/`Amp` are
   Suite-only — Saturator/Overdrive are the universal fallback.
9. **Creating a track/scene at a low index shifts everything after it.** Re-check indices
   (`get_session_info`) or append at the end (`index = -1`).
10. **Humanize in layers** — `humanize_clip_velocity(~0.08)` + `humanize_clip_timing(~0.04)`;
    apply twice if it still sounds programmed.
11. **Toggles don't tell you the prior state.** `toggle_arrangement_record`,
    `toggle_session_record`, `toggle_device` flip whatever is there. Parse the reply
    ("… is now on/off"); if it's not the state you wanted, toggle again and re-check. Read
    first where a getter exists (`get_metronome_state`).
12. **Warn before arming a track that has Arrangement content.** With arrangement record
    on, Live draws red overdub indicators on those clips — they look like deletion but are
    only a preview. Say so before arming, then confirm with `get_arrangement_length` and
    `get_track_info` that nothing changed. If the user reports "content deleted", verify
    with reads before anyone reaches for undo or reload (unsaved Session work is at risk).
13. **Read clip names before inferring harmony.** Users label clips with the chords
    ("verse – Am Em x 4"). The label gives *which* chords; the note timing gives *bars per
    chord* (the label doesn't — "x 4" can mean 2 bars each). Arrangement clips aren't
    visible over MCP: read the `.als` (`references/als-xml.md`).

## Session-jam patterns (song-agnostic)

- **One scene per feel/groove**; launching a scene starts all its clips bar-quantized.
- **Shared click track** (Simpler + clave at one pitch), a click clip per scene; mute to
  toggle.
- **A REC audio track per live instrument** — armed, monitored, for takes.
- **A muted NOTES track** whose clip *names* carry tips/roadmaps.
- **Count-in without Follow Actions:** click-only clip + 1–2-bar launch quantization;
  fire the groove during the count bar, it drops on the next downbeat.
- **Odd meters:** set the Set's signature over raw TCP (`set_signature`, below) so the
  grid and bar numbers match — one meter per Set. For scenes in different meters, use
  clip length instead: 5/4 = 5-beat clips, 7/8 = 3.5-beat clips — the same length for
  every clip in the scene **including the click**.
- **Whole song in one scene (through-composed):** full-song-length clips per track with
  an energy arc; **leave a track empty for a live player** (e.g. no bass clip for a
  bassist).
- **Label everything:** chords/patterns in `set_clip_name`, matching clip colors,
  paste-ready "Edit Info Text" blocks for the user.

### Working method that scales

Generate notes in a script → save JSON → push over the raw-TCP bulk path (or ≤140-note
MCP chunks) — deterministic, reviewable, revertible. High-pass synths/keys so a live bass owns the lows. Test one
section, get direction, then propagate.

## Timing: seconds → Live beats

Live's tempo and clip positions count **quarter notes**, whatever the meter.
- `set_tempo(pulse_bpm × 4 / pulse_unit)` — with an eighth-note pulse (`pulse_unit` 8),
  halve it; passing the eighth-note pulse straight in doubles the tempo.
- One bar = `beats_per_bar × 4 / pulse_unit` Live beats (4/4 → 4, 7/8 → 3.5, 11/8 → 5.5).
- **Map analysed audio through the real beat grid, not one BPM.** Played music drifts
  (150–171 BPM inside one song has been measured), so `beats = sec × BPM / 60` accumulates
  error over minutes. For a take recorded to Live's click, the fixed formula is exact.

```python
bt = np.asarray(beat_times); n = np.arange(len(bt))           # from foundation.json
def to_live_beats(t, pulse_unit):
    p = np.interp(t, bt, n)                                    # fractional pulse index
    p = np.where(t < bt[0], (t - bt[0]) / (bt[1] - bt[0]), p)  # extrapolate the ends
    p = np.where(t > bt[-1], n[-1] + (t - bt[-1]) / (bt[-1] - bt[-2]), p)
    return np.round(p * 4 / pulse_unit * 4) / 4                # Live beats, 16th grid
```

- **Pre-roll:** anything before the first tracked beat comes out negative, and notes at
  negative clip times never play. Shift the whole part by one bar and lengthen the clip.
- If `foundation.json` reports tempo drift above ~±3%, don't collapse to one BPM: build
  on the warped grid above and tell the user the Live tempo is the median.

## Bulk path: raw TCP on port 9877

The Remote Script takes one JSON command per connection on `127.0.0.1:9877` —
`{"type": <command>, "params": {…}}` — the same commands the MCP tools wrap, plus a few
with no MCP tool. Use it for bulk writes (it keeps thousands of notes out of the
conversation); use MCP tools for reads and verification. Sequential per clip.

```python
import json, socket
def live(cmd, **params):
    with socket.create_connection(("127.0.0.1", 9877), timeout=60) as s:
        s.sendall(json.dumps({"type": cmd, "params": params}).encode())
        buf = b""
        while chunk := s.recv(65536):
            buf += chunk
            try: return json.loads(buf)
            except json.JSONDecodeError: continue
        raise ConnectionError(f"incomplete reply: {buf[:200]!r}")

for i in range(0, len(notes), 300):
    r = live("add_notes_to_clip", track_index=T, clip_index=C, notes=notes[i:i + 300])
    assert r.get("status") == "success", r          # stop on the first failed chunk
```

**`scripts/push_notes.py`** does all of this: chunked push that exits non-zero on the
first failed chunk, `--clear` (including out-of-bounds notes), `--signature 11/8` with
read-back, and `--from-seconds foundation.json` for the beat-grid mapping and pre-roll
above. Standard library only; tested against a mock socket
(`tests/test_push_notes.py`).

**Time signature** (no MCP tool): `live("set_signature", numerator=11, denominator=8)`,
then read it back with `live("get_signature")` (verified on Live 12.4). It sets one global
meter for the Set —
the Live Object Model has no API for meter changes along the Arrangement.

**Audio files and warping — patched Remote Script only** (raw TCP, no MCP tool;
`references/remote-script-patch.md`, then restart Live): `create_audio_clip {track_index,
clip_index, file_path}` loads a file into an empty Session slot; `set_clip_warping` (Live
defers it — read back with `get_clip_info`); a working `add_warp_marker {beat_time,
sample_time}` (seconds) and `move_warp_marker {beat_time, distance}`; `set_clip_warp_mode`
with Live's real indices (`complex_pro` = 6; the stock script sends 5 = REX). These raise
real errors. `get_capabilities` → `remix_patch: 1` tells a patched script from the stock
one ("Unknown command") without writing anything. On the stock script never pass
`complex_pro`, and don't call `add_warp_marker`, `create_locator` or `delete_locator`.

## Local environment (this machine)

- `.mcp.json` in `~/dev/abletonAI/` runs `~/dev/abletonAI/.venv-ableton-mcp/bin/ableton-mcp`:
  the fork installed editable (branch `mcp-sdk-compat`, SDK 1.30.0 — see setup-install.md);
  Remote Script from the same checkout installed.
- Recording session output to audio: empty-slot record needs a UI click — use Resample
  workflow instead.
- Source doc (read-only): `~/dev/abletonAI/audio-analysis/WORKFLOW-ableton-mcp.md`.

Files in this skill

  • SKILL.md8.1 KB
  • references/setup-install.md3.4 KB
  • references/troubleshooting.md1.5 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.