Skip to main content
Glama

ableton12 — full-control MCP server for Ableton Live 12

A Python + uv MCP server that lets an LLM (Claude Code, Claude Desktop, any MCP client) drive Ableton Live 12 through the Live Object Model — and, uniquely, measure what it just made.

It is a drop-in superset of the upstream ahujasid/ableton-mcp: it keeps the 16 original tools (identical names, params and return values, so existing prompts/permissions keep working) and adds everything upstream can't do — 62 tools in total:

  • Device & instrument parameter control — read every parameter and actually change the tone: filter cutoff, oscillator type, reverb decay, macros, device bypass.

  • Mixer — volume, pan, sends, mute, solo, arm, color. Addresses the master bus and return tracks, not just regular tracks.

  • Tracks / clips / scenes / transport — create audio & return tracks, read & remove notes, loop settings, duplicate, delete, color, fire scenes, time signature, metronome, playhead.

  • Session → Arrangement capture — record a Session scene into the Arrangement so Live's exporter (Arrangement-only) can render it.

  • Ears — capture any single track (or the master / a return) to a WAV via a loopback device and analyze it: LUFS, true peak, 10-band spectrum, spectral centroid, transient punch, stereo width. Plus compare_audio for before/after A-B of a parameter change. This is what makes an autonomous measure → adjust → re-measure tuning loop possible instead of guessing.

  • Host automation (macOS) — launch Live, new Set, Save, Save As, open the Export dialog.

Scope: this repo is the MCP server + Remote Script only. The composition prompt-layer built on top of it (slash commands like /clip, /master, /dial, /export) lives elsewhere; every tool here is usable from any MCP client on its own.

Architecture

Two halves talk over TCP localhost:9877 using 4-byte length-prefixed JSON frames:

LLM ⇄ (stdio) ⇄  ableton12 MCP server  ⇄ (TCP 9877) ⇄  Remote Script (inside Live)
                 src/ableton12_mcp/                     remote_script/AbletonMCP/
                        │
                        └─ ffmpeg + loopback device ─► WAV ─► analysis (numpy/scipy/pyloudnorm)
  • MCP server (src/ableton12_mcp/server.py): FastMCP server named AbletonMCP. Each @mcp.tool() sends one command frame and returns the result. _host.py does the macOS-level automation, _record.py the loopback capture, _analysis.py the audio metrics.

  • Remote Script (remote_script/AbletonMCP/__init__.py): a ControlSurface running inside Live's embedded Python. A socket thread does pure I/O; every command — reads included — is marshaled onto Live's main thread via schedule_message + a reply queue (_run_on_main). That is the key correctness fix: upstream's device-parameter attempts crashed because reads ran off the main thread while writes ran on it.

Related MCP server: io.github.peterkolbe/ableton-for-ai

Requirements

Ableton Live 12

the Remote Script targets Live 12's Object Model

macOS

required for host automation (launch_ableton, save_set*, open_export_dialog) and for loopback capture (avfoundation). The Live-control tools themselves are OS-agnostic.

Python ≥ 3.10 + uv

brew install uv

ffmpeg (optional)

needed by record_audio / record_and_analyze — brew install ffmpeg

BlackHole (optional)

loopback device for the "ears" — brew install blackhole-2ch

Install

# 1. Clone and sync dependencies
git clone https://github.com/verove-jordan/ableton12-mcp.git
cd ableton12-mcp
uv sync

# 2. Install the Remote Script into Ableton's User Library
#    (quit Live first; the script backs up any existing AbletonMCP install)
./install.sh

# 3. In Ableton: Settings → Link, Tempo & MIDI → Control Surfaces → pick "AbletonMCP"
#    with Input = None and Output = None, then RESTART Ableton.
#    The status bar should read:  AbletonMCP (ableton12): listening on port 9877

# 4. Register the server with your MCP client — e.g. Claude Code, at user scope:
claude mcp add AbletonMCP -s user -- uvx --from "$(pwd)" ableton12
#    Then run /mcp to connect and call the `health` tool to verify.

Generic MCP client config (Claude Desktop, .mcp.json, …) — use an absolute path:

{
  "mcpServers": {
    "AbletonMCP": {
      "type": "stdio",
      "command": "uvx",
      "args": ["--from", "/absolute/path/to/ableton12-mcp", "ableton12"]
    }
  }
}

Only one process may bind port 9877 — make sure no old uvx ableton-mcp server is still running.

Optional: the "ears" (per-track capture)

record_audio records Live's output in realtime from a loopback audio input, so you need one:

  1. brew install ffmpeg blackhole-2ch

  2. Audio MIDI Setup → create a Multi-Output Device containing both your speakers/ headphones and BlackHole; set it as Live's output (Preferences → Audio) or the system output — that way you still hear playback while it is captured.

  3. macOS will prompt once for Microphone access for the app running the MCP server (capturing an audio input counts as mic use): System Settings → Privacy & Security → Microphone.

Capture is realtime — a window's wall-clock equals its musical length, so keep windows short (2–4 bars).

Optional: host automation permissions

save_set_as and open_export_dialog drive Live's menus with AppleScript keystrokes, which needs a one-time Accessibility grant for the app running the MCP server (Terminal / iTerm / your editor): System Settings → Privacy & Security → Accessibility. These routines are best-effort and depend on the running Live version's dialog layout — always verify the resulting file on disk rather than trusting the return value.

Tool catalog (62)

Session & transport: get_session_info, set_tempo, start_playback, stop_playback, set_time_signature, set_metronome, set_song_position, get_transport, health.

Tracks: get_track_info, create_midi_track, create_audio_track, create_return_track, set_track_name, delete_track, duplicate_track.

Mixer: set_track_volume, set_track_pan, set_track_send, set_track_mute, set_track_solo, set_track_arm, set_track_color.

Devices & parameters: get_device_parameters, set_device_parameter, set_device_enabled, delete_device, get_macros, set_macro.

Browser / loading: get_browser_tree, get_browser_items_at_path, load_instrument_or_effect, load_drum_kit.

Clips: create_clip, add_notes_to_clip, get_clip_notes, remove_notes_from_clip, set_clip_name, set_clip_loop, duplicate_clip, delete_clip, set_clip_color, fire_clip, stop_clip.

Scenes: create_scene, fire_scene, set_scene_name, delete_scene.

Session → Arrangement capture: set_arrangement_record, set_clip_trigger_quantization, capture_session_to_arrangement.

Metering: get_track_meter, get_master_meter (levels 0..1, only while playing).

Listening & analysis: record_audio, record_and_analyze, analyze_audio, compare_audio.

Host automation (macOS): launch_ableton, new_live_set, save_set, save_set_as, open_export_dialog.

Addressing the master bus and return tracks

Track-scoped tools (get_track_info, load_instrument_or_effect, get_device_parameters, set_device_parameter, set_device_enabled, delete_device, set_track_volume, set_track_pan, get_track_meter, record_audio, …) take an optional track argument that overrides the integer track_index:

  • track='master' → the master bus (this is how you build a mastering chain),

  • track='return:0' → return track 0 (return:N), fed by set_track_send.

Plain integer track_index calls are unchanged.

Parameter value semantics (read this before "changing the tone")

get_device_parameters(track, device) returns each parameter with name, value, min, max, is_quantized, value_items (enum labels) and display_value (e.g. "440 Hz", "Lowpass"). Always read before you write — ranges are device- and install-specific. Then set_device_parameter:

  • Continuous params: pass value in native units (within [min, max]), or value_normalized (0..1 → min + x*(max-min)). Values are clamped.

  • Quantized params (is_quantized=true): pass value as either the integer index or the exact value_items label (case-insensitive), or value_normalized to pick by fraction.

  • A parameter mapped to a macro reports is_enabled=false; writes to it are skipped and the reply says so (applied=false). Change it through the macro (set_macro) instead.

Mixer ranges: volume is a fader position 0..1, not dB (~0.85 ≈ 0 dB, 1.0 ≈ +6 dB — the reply reports the resulting dB). Pan is −1..+1. Sends are 0..1.

Typical workflow: load_instrument_or_effect → get_device_parameters → set_device_parameter. After structural edits (delete_track, create_*, delete_scene) re-read get_session_info, because indices shift.

What analyze_audio returns

Peak/RMS dBFS, crest factor, clipping; LUFS (lufs_integrated, lufs_short_term_max, lufs_range_lra) and true peak (true_peak_dbtp); a 10-band spectrum (spectrum_bands / spectrum_bands_db) plus a legacy 4-band; brightness (spectral_centroid_hz, spectral_rolloff_hz, spectral_flatness); transients (onset_strength, onset_rate_per_sec, band_crest_db per band — low-band crest ≈ kick punch); stereo (stereo_correlation, stereo_width, band_stereo_width); plus noise floor, DC offset and silence detection. loudness_method flags whether pyloudnorm or the numpy fallback produced the LUFS figures.

compare_audio(a, b) turns two of those into per-metric deltas in human terms with a one-line headline, suppressing sub-perceptual changes — the progress meter for a tuning loop.

Known limitation — no automation over time

The server can set a parameter to a static value, but it cannot write clip/device automation envelopes, so moves that evolve across an arrangement (a filter opening over 16 bars, a progressive L↔R pan sweep) are not directly authorable. Workarounds and the plan to close the gap are in docs/AUTOMATION_TODO.md.

Debugging

  • "Connection refused" / can't connect: Ableton isn't running, wasn't restarted after a script change, or the control surface isn't selected. Don't retry blindly — check those three.

  • Confirm Live holds the port: lsof -nP -iTCP:9877 -sTCP:LISTEN should show Live. If it shows a python/uvx process, a stale server has the port.

  • Remote Script logs: ~/Library/Preferences/Ableton/Live 12*/Log.txt — look for AbletonMCP (ableton12) ... initializing and listening on port. Use self.log_message; print() from the script is invisible.

  • After editing the Remote Script you must restart Ableton (or re-select the control surface). install.sh clears __pycache__; the health tool reports the loaded version so you can confirm the new build is active.

Credits

API-compatible with, and inspired by, ahujasid/ableton-mcp. Not affiliated with Ableton AG.

Available Tools

62 tools
add_notes_to_clipA

Add MIDI notes to a clip (additive — call repeatedly to build large clips).

Each note dict: pitch (0-127), start_time (beats), duration (beats),
velocity (1-127), mute (bool, optional).

Inputs: notes (required), clip_index (required), track_index (required). Returns: result

analyze_audioA

Analyze a rendered/captured audio file — the objective 'listening' step.

Returns peak/RMS dBFS, crest factor, clipping; LUFS (integrated/short-term/
LRA) and true peak (dBTP); a 10-band spectrum (+ legacy 4-band) with centroid,
rolloff and flatness; transient/punch (onset strength/rate, per-band crest);
stereo correlation + overall/per-band width; DC offset, noise floor and
leading/trailing silence. `loudness_method` says whether LUFS came from
pyloudnorm or the numpy fallback. Capture a track/section first (record_audio)
or render via the export path, then analyze. Needs numpy+soundfile.

Inputs: wav_path (required). Returns: result

capture_session_to_arrangementA

Record a Session scene into the Arrangement so the song can be exported.

Live's Export Audio/Video only renders the Arrangement, so a Session-view
loop must first be printed there. This automates the whole capture — no
manual Arrangement-record arming:

  1. stop, rewind to 1.1.1, force Session Record off, and (if tighten_launch)
     set clip-launch quantization to None for a tight start at bar 1,
  2. arm Arrangement Record (the ● button),
  3. fire scene `scene_index` — its clips begin printing into the Arrangement,
  4. wait one full pass (`length_beats` + `tail_beats`), polling the playhead,
  5. stop, disarm record, restore quantization, rewind, return to Arrangement.

length_beats = bars * time_signature_numerator (e.g. 128 bars of 4/4 = 512).
`tail_beats` lets the final notes ring before stopping. Re-recording the same
span overwrites the previously captured Arrangement region for the scene's
tracks, so re-exports stay clean.

wait=True (default) blocks until the pass finishes and returns the result.
wait=False arms + fires and returns immediately (then call stop_playback and
set_arrangement_record(False) yourself once the playhead reaches length_beats).
max_wait_seconds caps the blocking wait (0 = auto: one pass + 15 s headroom).

Inputs: scene_index (required), length_beats (required), wait, tail_beats, +2 more. Returns: result

compare_audioA

Diff two audio files (b relative to a) into human-readable deltas — loudness, per-band level, brightness (centroid), punch (low-band crest), width and dynamics, plus a one-line headline. Sub-perceptual changes are suppressed. This is the closed loop's progress meter: capture before/after a parameter move and compare to confirm the change helped.

Inputs: path_a (required), path_b (required). Returns: result

create_audio_trackB

Create a new audio track. index=-1 appends at the end.

Inputs: index. Returns: result

create_clipA

Create a new empty MIDI clip. length is in BEATS (not bars).

Inputs: clip_index (required), track_index (required), length. Returns: result

create_midi_trackA

Create a new MIDI track. index=-1 appends at the end. Re-read get_session_info afterwards to learn the real new index.

Inputs: index. Returns: result

create_return_trackA

Create a new return track (appended after existing returns).

Inputs: no named parameters. Returns: result

create_sceneA

Create a new scene. index=-1 appends at the end.

Inputs: index. Returns: result

delete_clipB

Delete the clip in a clip slot.

Inputs: clip_index (required), track_index (required). Returns: result

delete_deviceB

Delete a device from a track. track='master'/'return:N' targets those tracks.

Inputs: track_index (required), device_index (required), track. Returns: result

delete_sceneA

Delete a scene. Higher scene indices shift down.

Inputs: scene_index (required). Returns: result

delete_trackA

Delete a track. All higher track indices shift down — re-read get_session_info afterwards.

Inputs: track_index (required). Returns: result

duplicate_clipB

Duplicate a clip into the next clip slot on the same track.

Inputs: clip_index (required), track_index (required). Returns: result

duplicate_trackA

Duplicate a track (with its devices and clips). Re-read get_session_info afterwards to learn indices.

Inputs: track_index (required). Returns: result

fire_clipB

Start playing a clip (launches the clip slot).

Inputs: clip_index (required), track_index (required). Returns: result

fire_sceneA

Launch a scene (fires every track's clip in that scene row).

Inputs: scene_index (required). Returns: result

get_browser_items_at_pathA

List browser items at a path like 'instruments/Operator' or 'drums'. Each item reports name, is_folder, is_loadable and uri.

Inputs: path (required). Returns: result

get_browser_treeA

Get the top-level browser categories ('all', 'instruments', 'sounds', 'drums', 'audio_effects', 'midi_effects'). Use get_browser_items_at_path to drill in and find loadable URIs.

Inputs: category_type. Returns: result

get_clip_notesA

Read all MIDI notes from a clip. Returns JSON with a list of notes (pitch, start_time, duration, velocity, mute, and note_id when available).

Inputs: clip_index (required), track_index (required). Returns: result

get_device_parametersA

List every automatable parameter of a device on a track.

Returns JSON with the device name and a list of parameters, each:
index, name, value, min, max, is_quantized, value_items (enum labels for
quantized params, else null), display_value (e.g. '440 Hz', 'Lowpass'),
default_value, is_enabled. Use this to discover what you can change, then
call set_device_parameter. track='master'/'return:N' targets those tracks.

Inputs: track_index (required), device_index (required), track. Returns: result

get_macrosA

List the macro controls of a Rack device (Instrument/Audio/MIDI/Drum Rack). Returns JSON like get_device_parameters but limited to the rack's macros. Set them with set_macro (or set_device_parameter).

Inputs: track_index (required), device_index (required). Returns: result

get_master_meterA

Read the master bus output meter (0..1). Sample while a scene is playing to gauge overall level / spot clipping (level near 1.0 = too hot).

Inputs: no named parameters. Returns: result

get_session_infoA

Get detailed information about the current Ableton session (tempo, time signature, track/return/scene counts, master mixer).

Inputs: no named parameters. Returns: result

get_track_infoA

Get detailed info about a track: name, mute/solo/arm, volume/pan, clip slots, and the ordered list of devices (with their indices).

Pass track='master' or track='return:0' to inspect the master bus or a
return track (those have no clip slots).

Inputs: track, track_index. Returns: result

get_track_meterA

Read a track's output meter (0..1) for left/right and overall level. track can be an int index, 'master', or 'return:N'. Meters only move while audio plays — fire a clip/scene first, then sample (call a few times).

Inputs: track. Returns: result

get_transportA

Report transport/record state: is_playing, record_mode (Arrangement Record ● armed?), session_record, current_song_time (beats), back_to_arranger, clip_trigger_quantization, tempo and time signature. Use it to verify a capture is running and to watch the playhead advance.

Inputs: no named parameters. Returns: result

healthA

Diagnostic: confirm the connection and report the Remote Script version that is actually loaded in Ableton (useful after reinstalling the script).

Inputs: no named parameters. Returns: result

launch_abletonA

Launch (or focus) Ableton Live 12, optionally opening a .als, then wait for the AbletonMCP control-surface bridge to come up on :9877. Use this to start Ableton before composing, or to reopen a saved project.

Inputs: als_path. Returns: result

load_drum_kitB

Load a Drum Rack, then load the first loadable kit found at kit_path.

Inputs: kit_path (required), rack_uri (required), track_index (required). Returns: result

load_instrument_or_effectA

Load an instrument or effect device onto a track by its browser URI.

Discover URIs with get_browser_tree / get_browser_items_at_path. After
loading, use get_device_parameters + set_device_parameter to dial it in.
Pass track='master' or track='return:0' to load onto the master bus or a
return track (e.g. a Reverb on a return, or the master-bus chain).

Inputs: uri (required), track_index (required), track. Returns: result

new_live_setA

File ▸ New Live Set (Cmd-N) for a clean slate. The control surface is a global preference, so the :9877 bridge survives. Requires Accessibility.

Inputs: no named parameters. Returns: result

open_export_dialogA

Open Export Audio/Video (Cmd-Shift-R) and copy target_path to the clipboard for pasting into the save sheet. Returns the remaining steps; does NOT press Render (you confirm the export). Requires Accessibility.

Inputs: format_hint, target_path. Returns: result

record_and_analyzeA

Capture source (see record_audio) then analyze it in one call — the single primitive the tuning loop uses: change a parameter, then record_and_analyze(source=track, bars=2, scene=N) to read the result. Returns {capture, analysis}.

Inputs: bars, solo, scene, device, +3 more. Returns: result

record_audioA

Capture Live's audio output to a WAV via a loopback device (BlackHole) — the per-track 'ears'. Give a duration as bars (resolved from the session tempo/meter) or seconds; capture is REALTIME so prefer 2–4 bars.

source: a track index (int) to capture ONE track — it is soloed for the
capture and the prior solo state is restored — or 'master' / 'return:N'
(no solo). scene: the Session scene to fire so clips actually play (this
project composes in Session view — pass the arrangement scene index);
omit scene to play the Arrangement from position_beats instead.

Needs BlackHole + a Multi-Output Device set as Live's output, ffmpeg, and a
one-time Microphone grant. If no loopback device is found the reply explains
how to install it and names the manual-export fallback. Returns the WAV path
(in the temp dir) — feed it to analyze_audio / compare_audio.

Inputs: bars, solo, scene, device, +7 more. Returns: result

remove_notes_from_clipA

Remove MIDI notes from a clip within a time/pitch region. Defaults clear the whole clip (from_time=0, full length, all pitches). time_span=None means 'to the end of the clip'.

Inputs: clip_index (required), track_index (required), from_time, time_span, +2 more. Returns: result

save_setA

File ▸ Save (Cmd-S) — for a Set already saved to disk. Requires Accessibility.

Inputs: no named parameters. Returns: result

save_set_asA

File ▸ Save As to a specific path, e.g. '.../projects// Project/.als'. Drives the macOS save sheet via AppleScript (best-effort) and returns expected_path — verify the file exists afterwards. Requires Accessibility.

Inputs: als_path (required). Returns: result

set_arrangement_recordA

Arm/disarm Arrangement (global) Record — the transport's ● button. With it ON, launching Session clips/scenes records them into the Arrangement timeline. This is the capability that lets a Session-view loop be captured for export (Live's exporter only renders the Arrangement). For the full automated capture use capture_session_to_arrangement instead.

Inputs: on. Returns: result

set_clip_colorA

Set a clip's color as a packed RGB integer (0xRRGGBB).

Inputs: color (required), clip_index (required), track_index (required). Returns: result

set_clip_loopA

Set a clip's loop attributes (only the ones you pass are changed): looping on/off, loop_start/loop_end (beats), start_marker/end_marker.

Inputs: clip_index (required), track_index (required), looping, loop_end, +3 more. Returns: result

set_clip_nameB

Set the name of a clip.

Inputs: name (required), clip_index (required), track_index (required). Returns: result

set_clip_trigger_quantizationA

Set the global clip-launch quantization by index (0 = None, which launches clips immediately). capture_session_to_arrangement sets this to None for a tight start and restores it afterwards; exposed here for manual control.

Inputs: value. Returns: result

set_device_enabledA

Turn a device on or off (its bypass / 'Device On' switch). track='master'/'return:N' targets those tracks.

Inputs: on (required), track_index (required), device_index (required), track. Returns: result

set_device_parameterA

Set one device parameter — this is how you change a sound's tone.

- parameter: the parameter index (int) OR its exact name (str, case-insensitive).
- value: native units. For a continuous param a float in [min, max]
  (e.g. a frequency/dB/ms). For a quantized param, either an integer index
  into value_items or the exact value_items label string (e.g. "Lowpass").
- value_normalized: alternative to value, a 0.0-1.0 fraction mapped to
  min + x*(max-min); for quantized params it picks the value_items index.

Provide exactly one of value / value_normalized. The reply reports the
resulting display_value and whether the write applied (a parameter driven
by a macro is not writable).

Inputs: parameter (required), track_index (required), device_index (required), track, +2 more. Returns: result

set_macroA

Set a Rack macro by index (0-based) or name. Same value/value_normalized semantics as set_device_parameter.

Inputs: macro (required), track_index (required), device_index (required), value, +1 more. Returns: result

set_metronomeA

Turn the metronome on or off.

Inputs: on (required). Returns: result

set_scene_nameC

Set a scene's name.

Inputs: name (required), scene_index (required). Returns: result

set_song_positionA

Move the transport playhead to a position in beats from song start.

Inputs: beats (required). Returns: result

set_tempoB

Set the session tempo in BPM.

Inputs: tempo (required). Returns: result

set_time_signatureA

Set the song time signature, e.g. numerator=3, denominator=4 for 3/4.

Inputs: numerator (required), denominator (required). Returns: result

set_track_armA

Arm (on=True) or disarm (on=False) a track for recording.

Inputs: on (required), track_index (required). Returns: result

set_track_colorA

Set a track's color as a packed RGB integer (0xRRGGBB, e.g. 16711680 = red).

Inputs: color (required), track_index (required). Returns: result

set_track_muteA

Mute (on=True) or unmute (on=False) a track.

Inputs: on (required), track_index (required). Returns: result

set_track_nameC

Set the name of a track.

Inputs: name (required), track_index (required). Returns: result

set_track_panA

Set a track's pan, -1.0 (hard left) .. 0.0 (center) .. +1.0 (hard right). track='master'/'return:N' targets those tracks.

Inputs: value (required), track_index (required), track. Returns: result

set_track_sendC

Set a track's send level (0.0-1.0) to return track send_index (0-based).

Inputs: send_index (required), track_index (required), value, value_normalized. Returns: result

set_track_soloA

Solo (on=True) or unsolo (on=False) a track.

Inputs: on (required), track_index (required). Returns: result

set_track_volumeA

Set a track's volume fader (0.0-1.0). NOTE: this is the fader position, not dB — ~0.85 ≈ 0 dB (unity), 1.0 ≈ +6 dB. value and value_normalized are equivalent here (the fader range is already 0..1). Reply reports the dB. track='master' sets the master fader.

Inputs: track_index (required), track, value, value_normalized. Returns: result

start_playbackA

Start the session transport.

Inputs: no named parameters. Returns: result

stop_clipA

Stop a playing clip slot.

Inputs: clip_index (required), track_index (required). Returns: result

stop_playbackA

Stop the session transport.

Inputs: no named parameters. Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.4/5.0

    Scored across 62 tools

    Disambiguation4/5

    Most tools target distinct resources and actions, but there is some intentional overlap between get_device_parameters/get_macros and set_device_parameter/set_macro, and record_and_analyze is a composite of record_audio and analyze_audio. These are documented clearly enough to avoid confusion in practice.

    Naming Consistency5/5

    Tool names overwhelmingly follow a verb_noun snake_case pattern (e.g., create_midi_track, set_device_parameter, delete_scene). Minor exceptions like health, new_live_set, and save_set_as are still readable and do not disrupt the overall predictability.

    Tool Count2/5

    At 62 tools, the server is far beyond the 25+ threshold that indicates an over-heavy toolset. While Ableton is a complex domain, the count feels overwhelming and many tools could be consolidated (e.g., record_and_analyze already merges two).

    Completeness4/5

    The toolset covers the full creative workflow: session/track/clip management, device control, scenes, transport, audio capture, analysis, and comparison. The main gap is that export is not fully automated—open_export_dialog requires manual confirmation—but the capture-to-arrangement path fills most of the pipeline.

    Related MCP Connectors

    Related MCP Servers

    • F
      license
      B
      quality
      D
      maintenance
      MCP server for controlling Ableton Live, enabling AI assistants to interact with Live sessions through tools for track/clip/scene management, playback control, and device parameter adjustments.
      48
      -
    • A
      license
      Not graded
      quality
      C
      maintenance
      An MCP server that exposes Ableton Live control (session state, transport, tracks, devices, clips, MIDI note editing) as tools for LLM agents, enabling natural language manipulation of a Live session.
      1
      MIT