TwelveTake-Studios/reaper-mcp
π π π πͺ π§ - MCP server enabling AI assistants to control REAPER DAW for mixing, mastering, MIDI composition, and full music production with 129 tools
Quick Install
{
"mcpServers": {
"twelvetake-studios-reaper-mcp": {
"command": "npx",
"args": [
"-y",
"twelvetake-studios-reaper-mcp"
]
}
}
}Using an AI coding agent (Claude Code, Cursor, etc.)? Copy a ready-made prompt that tells it to fetch the setup instructions and install this server for you.
Documentation Overview
TwelveTake REAPER MCP
A TwelveTake Studios project.
A comprehensive Model Context Protocol (MCP) server that enables AI assistants to control REAPER DAW for mixing, mastering, MIDI composition, and full music production workflows.
Version: 1.6.0
Why This Server
Workflow Automation, Not Just API Wrappers
Most MCP servers just wrap REAPER's API and call it a day. This one includes production workflow helpers that handle multi-step operations in a single call:
| Tool | What it does for you |
|---|---|
setup_sidechain_compression() | Creates send, routes to channels 3-4, configures ReaComp's detector input β complete sidechain setup in one call |
add_mastering_chain() | Adds ReaEQ β ReaComp β ReaEQ β ReaLimit to master track with proper signal flow |
add_parallel_compression() | Creates a bus track, sets up the send, adds compressor β NY-style compression ready to blend |
create_bus() | Creates a submix track and routes your specified tracks to it |
get_project_summary() | Returns track count, all track names/volumes/pans/FX, markers, regions, tempo, time signature β everything your AI needs in one call |
Zero Configuration
- File-based communication works immediately β no network setup, no ports to configure
- Stock REAPER Lua only β the bridge script has no dependencies, nothing extra to install in REAPER
- Copy the script, run it, connect your AI assistant
176 Tools Covering Real Production Needs
- Full FX control β add/remove plugins, get/set any parameter by index, manage presets, bypass
- FX parameter automation β automate any plugin knob (flanger depth, filter cutoff, etc.)
- Complete routing β sends, receives, sidechain routing to specific channel pairs
- Automation β create envelopes, add/edit points, set automation modes
- MIDI β create items, add notes individually or in batches, edit velocities
- MIDI editing β transpose, quantize with swing, humanize, snap to a scale, stretch, legato, strum, velocity ramps β each targetable by pitch range, beat window, or channel
- Audio items β import, split, duplicate, fade, position, mute
- Markers & regions β create, edit, navigate, render by region
Requirements
- REAPER (any recent version; full live suite green through REAPER 7.77)
- Python 3.8+ (for the MCP server)
- An MCP-compatible AI assistant
Installation
1. Install the Bridge Script in REAPER
The bridge script runs inside REAPER and handles communication with the MCP server.
- Copy
reaper_mcp_bridge.luato your REAPER Scripts folder:- Windows:
%APPDATA%\REAPER\Scripts\ - macOS:
~/Library/Application Support/REAPER/Scripts/ - Linux:
~/.config/REAPER/Scripts/
- Windows:
- In REAPER: Actions β Show action list β Load ReaScript
- Select
reaper_mcp_bridge.luaand click Run
You should see "REAPER MCP Bridge (File-based, Full API) started" in REAPER's console.
2. Install and Configure the MCP Server
The server is published on PyPI as twelvetake-reaper-mcp. The simplest path is to let your
MCP client launch it with uvx (or pipx) β nothing to install by hand.
Add it to your MCP client's configuration (e.g. .mcp.json, or your client's MCP settings):
{
"mcpServers": {
"reaper": {
"command": "uvx",
"args": ["twelvetake-reaper-mcp"]
}
}
}
VS Code uses a top-level
serverskey with"type": "stdio"instead ofmcpServers.
To confirm the server starts on its own:
uvx twelvetake-reaper-mcp
# or: pipx run twelvetake-reaper-mcp
It waits quietly for a client to connect β press Ctrl+C to stop.
3. Verify
With REAPER open and the bridge running, ask your assistant "how many tracks are in my project?" β a number back means the server, bridge, and REAPER are all talking.
Run from source (for development)
To work on the server itself, run it from a clone instead of from PyPI. Install the dependencies:
pip install -r requirements.txt # or: pip install mcp httpx
Point your MCP client at the local script:
{
"mcpServers": {
"reaper": {
"command": "python",
"args": ["path/to/reaper_mcp_server.py"]
}
}
}
Then check the connection with:
python test_connection.py
Nix flake (optional)
If you use Nix, the repo ships a flake-based dev shell that provides Python 3.12 and creates/activates a virtualenv for you:
# Enter the dev shell manually
nix develop
# Or, with direnv, auto-activate on cd:
direnv allow
Then install the dependencies as usual:
pip install -r requirements.txt
This pins the Python version and keeps dependencies isolated from your system.
Note: the
x86_64-linuxdev shell is tested and working. The macOS (Darwin) shells are provided but have not been tested β confirmation from a macOS user is welcome.
Communication Modes
The file-based bridge is the supported path β it is reliable and needs no extra setup. HTTP mode is deprecated (see below).
File-Based (Default, Recommended)
Uses JSON files for communication. More reliable, no network configuration needed. This is the only actively maintained path; all tools are guaranteed to work here.
MCP Server REAPER Bridge
β β
βββ writes request_N.json βββββΊβ
β βββ processes request
ββββ reads response_N.json βββββ€
Bridge directory: %APPDATA%\REAPER\Scripts\mcp_bridge_data
HTTP Mode (Deprecated)
Deprecated as of v1.2.1. The HTTP bridges (
reaper_web_server.lua/reaper_web_server.py) are kept for existing users but are no longer maintained and will not receive new tools. They may be removed in a future major release (v2.0). Use the file bridge instead.
Uses HTTP requests on localhost. Requires additional setup:
- Lua HTTP bridge: Requires LuaSocket (install via ReaPack β "sockmonkey")
- Python HTTP bridge: Requires Python enabled in REAPER preferences
# Set environment variable to use HTTP mode
REAPER_COMM_MODE=http python reaper_mcp_server.py
Default port: 9000
Quick Start Examples
Basic Track Operations
"How many tracks are in my project?"
"Create a new track called 'Vocals'"
"Set track 0 volume to -6dB"
"Mute track 2"
"Solo the drums track"
Mixing
"Add ReaComp to the bass track"
"Set up sidechain compression from the kick to the bass"
"Create a drum bus and route tracks 0-3 to it"
"Add a mastering chain to the master track"
FX and Parameters
"What plugins are on track 0?"
"Get the parameters for the compressor on track 1"
"Set the threshold to -20dB"
"Bypass the EQ on the vocal track"
MIDI Composition
"Create a 4-bar MIDI item on track 0"
"Add a C major chord at the start"
"Get all the notes in the MIDI item"
"Set the velocity of note 0 to 100"
Transport and Navigation
"Play the project"
"Stop playback"
"Set the cursor to 30 seconds"
"Add a marker called 'Chorus' at the current position"
Project Management
"What's the project tempo?"
"Set the tempo to 120 BPM"
"Save the project"
"Render to D:/Output/mix.wav"
Tool Reference
Track Operations (23 tools)
| Tool | Description |
|---|---|
get_track_count() | Get total number of tracks (excluding master) |
get_track(index) | Get track info (name, volume, pan, mute, solo) |
get_all_tracks() | Get info for all tracks |
get_master_track() | Get master track info |
insert_track(index, name) | Create a new track |
delete_track(index) | Delete a track |
set_track_name(index, name) | Rename a track |
set_track_volume(index, db) | Set volume in dB |
set_track_pan(index, pan) | Set pan (-1 to 1) |
set_track_mute(index, mute) | Mute/unmute track |
set_track_solo(index, solo) | Solo/unsolo track |
set_track_phase(index, invert) | Invert phase |
set_track_width(index, width) | Set stereo width (0-2) |
set_track_color(index, r, g, b) | Set track color |
get_track_peak(index, channel) | Get current peak level (dB) |
get_track_peak_hold(index, channel) | Get held peak since last reset (dB) |
clear_all_peak_indicators() | Reset peak hold on all tracks |
get_track_master_send(index) | Get master/parent send state |
set_track_master_send(index, enabled) | Enable/disable master send |
set_track_as_folder(index, depth) | Set as folder parent/child |
arm_track(index, arm) | Arm for recording |
set_track_input(index, input) | Set record input |
set_track_monitor(index, mode) | Set monitor mode |
FX Operations (16 tools)
| Tool | Description |
|---|---|
track_fx_get_count(index) | Count FX on track |
track_fx_get_list(index) | List all FX with details |
track_fx_add_by_name(index, name, position?) | Add FX plugin (optionally at position) |
track_fx_move(index, fx_index, new_position) | Reorder FX in the chain |
track_fx_delete(index, fx_index) | Remove FX |
track_fx_get_name(index, fx_index) | Get FX name |
track_fx_get_enabled(index, fx_index) | Check if enabled |
track_fx_set_enabled(index, fx_index, enabled) | Enable/bypass FX |
track_fx_get_num_params(index, fx_index) | Count parameters |
track_fx_get_param_name(index, fx_index, param) | Get parameter name |
track_fx_get_param(index, fx_index, param) | Get parameter value |
track_fx_set_param(index, fx_index, param, value) | Set parameter value |
get_fx_presets(index, fx_index) | List available presets |
get_fx_preset(index, fx_index) | Get current preset |
set_fx_preset(index, fx_index, name) | Load preset |
save_fx_preset(index, fx_index, name) | Save current settings as preset |
ReaEQ Operations (5 tools)
Dedicated ReaEQ band control using REAPER's EQ-specific API, which handles ReaEQ's non-linear parameter curves (dB gain, log frequency, log Q) correctly.
| Tool | Description |
|---|---|
find_eq(track, instantiate?) | Find ReaEQ on a track (optionally add it) |
get_eq_bands(track, fx) | Read all ReaEQ bands with human-readable values |
set_eq_band(track, fx, bandtype, bandidx, paramtype, value, is_normalized?) | Set a band parameter (Hz, dB, or Q) |
get_eq_band_enabled(track, fx, bandtype, bandidx?) | Check whether a band is enabled |
set_eq_band_enabled(track, fx, bandtype, bandidx?, enabled?) | Enable/disable a band |
Take FX Operations (11 tools)
Per-take (per-item) FX, mirroring the track FX tools. Every take is addressed by
(track_index, item_index, take_index).
| Tool | Description |
|---|---|
take_fx_get_count(track, item, take) | Count FX on a take |
take_fx_get_list(track, item, take) | List all take FX with details |
take_fx_add_by_name(track, item, take, name) | Add FX plugin to a take |
take_fx_delete(track, item, take, fx) | Remove FX from a take |
take_fx_get_name(track, item, take, fx) | Get take FX name |
take_fx_get_enabled(track, item, take, fx) | Check if enabled |
take_fx_set_enabled(track, item, take, fx, enabled) | Enable/bypass take FX |
take_fx_get_num_params(track, item, take, fx) | Count parameters |
take_fx_get_param_name(track, item, take, fx, param) | Get parameter name |
take_fx_get_param(track, item, take, fx, param) | Get parameter value |
take_fx_set_param(track, item, take, fx, param, value) | Set parameter value |
Take Management & Comping (7 tools)
Multi-take workflows: list/switch/delete takes, explode/crop, REAPER 7 fixed-lane comping.
| Tool | Description |
|---|---|
get_takes(track, item) | List all takes (name + active flag) |
get_active_take(track, item) | Get the active take index |
set_active_take(track, item, take) | Switch which take plays |
explode_takes(track, item) | Explode takes to overlapping items (in place) |
crop_to_active_take(track, item) | Keep only the active take |
delete_take(track, item, take) | Delete a specific take |
select_comp_lane(track, lane) | Play one fixed lane exclusively (lane comping) |
Routing (9 tools)
| Tool | Description |
|---|---|
create_send(src, dest) | Create send between tracks |
delete_send(index, send_index) | Remove a send |
set_send_volume(index, send_index, db) | Set send level |
get_track_num_sends(index) | Count sends from track |
set_send_dest_channels(index, send_index, chan) | Route to specific channels |
set_send_source_channels(index, send_index, chan) | Set source channels |
setup_sidechain_send(src, dest, db) | Create sidechain send |
configure_reacomp_sidechain(index, fx_index, use) | Configure ReaComp sidechain |
setup_sidechain_compression(trigger, target, fx, db) | Complete sidechain setup |
Transport (10 tools)
| Tool | Description |
|---|---|
play() | Start playback |
stop() | Stop playback |
pause() | Pause playback |
record() | Start recording |
get_play_state() | Get current state (playing/paused/recording) |
get_cursor_position() | Get edit cursor position (seconds) |
set_cursor_position(seconds) | Move edit cursor |
get_play_position() | Get playback position (seconds) |
toggle_repeat() | Toggle loop mode |
get_repeat_state() | Check if looping |
Project (15 tools)
| Tool | Description |
|---|---|
get_project_summary() | Get comprehensive project state in one call |
save_project() | Save current project |
create_project(name) | Create new project |
open_project(path) | Open project file |
get_project_path() | Get project directory |
get_project_name() | Get project filename |
get_project_length() | Get project length (seconds) |
get_tempo() | Get project tempo (BPM) |
set_tempo(bpm) | Set project tempo |
get_time_signature() | Get time signature |
set_time_signature(num, denom) | Set time signature |
render_project(path, start, end, tail) | Render to audio file |
render_region(index, path) | Render specific region |
zoom_to_selection() | Zoom to time selection |
zoom_to_project() | Zoom to show entire project |
MIDI Operations (8 tools)
| Tool | Description |
|---|---|
create_midi_item(track, pos, length) | Create empty MIDI item |
get_midi_item(track, item) | Get MIDI item info |
add_midi_note(track, item, pitch, vel, start_beat, length_beats, chan) | Add single note (beats) |
add_midi_notes_batch(track, item, notes) | Add multiple notes |
get_midi_notes(track, item) | Get all notes |
delete_midi_note(track, item, note) | Delete a note |
clear_midi_item(track, item) | Delete all notes |
set_midi_note_velocity(track, item, note, vel) | Change note velocity |
MIDI Utilities (13 tools)
Editing tools for notes that already exist. Every one takes the same optional filter β a pitch range, an onset window in beats from the item start, and a channel β so you can target a phrase without selecting anything by hand. Timing is in beats, pitch in semitones. Each is one undo step.
| Tool | Description |
|---|---|
transpose_midi_notes(track, item, semitones, ...) | Shift pitch; notes pushed outside 0-127 are left alone, never wrapped |
snap_midi_notes_to_scale(track, item, root, mode, ...) | Snap off-key notes onto a scale (named or a custom interval list) |
quantize_midi_notes(track, item, grid, strength, swing, ...) | Snap onsets to the project grid, with strength and swing |
nudge_midi_notes(track, item, amount_beats, ...) | Shift notes in time; lengths preserved |
stretch_midi_notes(track, item, factor, pivot_beat, ...) | Scale timing about a pivot (half-time / double-time) |
legato_midi_notes(track, item, mode, voice, ...) | Close the gaps in a line, or set every note to one length |
humanize_midi_notes(track, item, timing, velocity, seed, ...) | Seeded, reproducible timing + velocity jitter |
strum_midi_notes(track, item, spread_beats, direction, ...) | Roll a chord out into a strum |
ramp_midi_note_velocities(track, item, start_vel, end_vel, ...) | Linear velocity ramp across a phrase (crescendo) |
scale_midi_note_velocities(track, item, mode, ratio, ...) | Multiply / set / compress velocities |
set_midi_note(track, item, note, ...) | Edit one note's pitch, velocity, timing, channel |
get_selected_midi_notes(track, item) | Read the notes selected in REAPER's editor |
remove_overlapping_midi_notes(track, item, mode, ...) | Trim or delete overlapping same-pitch notes |
remove_overlapping_midi_notes is the only one here that can remove notes; the rest only move
what is already there. It is flagged destructive so a client can prompt first.
Audio Items (17 tools)
| Tool | Description |
|---|---|
insert_audio_file(track, path, pos) | Import audio file |
get_track_items(track) | List all items on track |
get_item_info(track, item) | Get item details |
set_item_position(track, item, pos) | Move item |
set_item_length(track, item, length) | Change item length |
delete_item(track, item) | Delete item |
duplicate_item(track, item) | Duplicate item |
split_item(track, item, pos) | Split item at position |
set_item_mute(track, item, mute) | Mute/unmute item |
set_item_volume(track, item, db) | Set item volume |
set_item_fade_in(track, item, length) | Set fade-in |
set_item_fade_out(track, item, length) | Set fade-out |
select_all_items() | Select all items |
unselect_all_items() | Deselect all items |
get_selected_items() | Get selected items |
copy_selected_items() | Copy to clipboard |
paste_items() | Paste from clipboard |
Markers & Regions (8 tools)
| Tool | Description |
|---|---|
add_marker(pos, name, color) | Add marker |
add_region(start, end, name, color) | Add region |
get_markers() | Get all markers |
get_regions() | Get all regions |
delete_marker(index) | Delete marker |
delete_region(index) | Delete region |
go_to_marker(index) | Jump to marker |
go_to_region(index) | Jump to region start |
Automation (8 tools)
| Tool | Description |
|---|---|
get_track_envelope(track, name) | Get envelope by name |
get_envelope_point_count(track, name) | Count envelope points |
add_envelope_point(track, name, time, value, shape) | Add automation point |
get_envelope_points(track, name) | Get all points |
delete_envelope_point(track, name, index) | Delete point |
clear_envelope(track, name) | Clear all points |
set_track_automation_mode(track, mode) | Set automation mode |
arm_track_envelope(track, name, arm) | Arm envelope for recording |
FX Parameter Automation (5 tools)
| Tool | Description |
|---|---|
get_fx_envelope(track, fx, param) | Get/create envelope for any FX parameter |
add_fx_envelope_point(track, fx, param, time, value, shape) | Add automation point to FX parameter |
get_fx_envelope_points(track, fx, param) | Get all points from FX envelope |
delete_fx_envelope_point(track, fx, param, point) | Delete point from FX envelope |
clear_fx_envelope(track, fx, param) | Clear all points from FX envelope |
Selection & Editing (11 tools)
| Tool | Description |
|---|---|
undo() | Undo last action |
redo() | Redo last undone action |
get_undo_state() | Get undo/redo state |
select_track(index, exclusive) | Select a track |
select_all_tracks() | Select all tracks |
unselect_all_tracks() | Deselect all tracks |
get_selected_tracks() | Get selected track indices |
set_time_selection(start, end) | Set time selection |
get_time_selection() | Get time selection |
clear_time_selection() | Clear time selection |
delete_selected_items() | Delete selected items |
Mixing Helpers (6 tools)
| Tool | Description |
|---|---|
add_mastering_chain() | Add EQβCompβEQβLimiter to master |
add_parallel_compression(track, db) | Set up NY compression |
create_bus(name, tracks) | Create submix bus |
add_eq(track) | Add ReaEQ |
add_compressor(track) | Add ReaComp |
add_limiter(track) | Add ReaLimit |
Advanced (4 tools)
| Tool | Description |
|---|---|
run_action(action_id) | Run REAPER action by ID |
run_action_by_name(name) | Run action by name |
get_track_fx_chunk(track, fx) | Get raw FX state data |
cut_selected_items() | Cut items to clipboard |
Track Indexing
- Regular tracks: 0-based index (first track = 0)
- Master track: Use index
-1
"Set the master track volume to -3dB" β track_index = -1
"Mute track 1" β track_index = 1 (second track)
Common Plugin Names
Use these names with track_fx_add_by_name():
| Plugin | Name |
|---|---|
| EQ | ReaEQ |
| Compressor | ReaComp |
| Limiter | ReaLimit |
| Gate | ReaGate |
| Delay | ReaDelay |
| Reverb | ReaVerbate or ReaVerb |
Third-party plugins use their full name as shown in REAPER's FX browser.
Troubleshooting
"Cannot connect to REAPER"
- Ensure REAPER is running
- Ensure the bridge script is running (check REAPER's console)
- For file mode: verify the bridge directory exists
- For HTTP mode: check port 9000 isn't blocked
"Track not found"
- Track indices are 0-based
- Use
-1for master track - Check track count with
get_track_count()
Bridge script won't load
- Lua: Ensure LuaSocket is installed (ReaPack β "sockmonkey")
- Python: Enable Python in REAPER preferences
Slow response
- File-based mode has ~50ms latency per call
- Batch operations when possible (e.g.,
add_midi_notes_batch)
Environment Variables
| Variable | Default | Description |
|---|---|---|
REAPER_COMM_MODE | file | Communication mode (file or http) |
REAPER_BRIDGE_DIR | %APPDATA%\REAPER\Scripts\mcp_bridge_data | File bridge directory |
REAPER_HOST | localhost | HTTP bridge host |
REAPER_PORT | 9000 | HTTP bridge port |
License
MIT License - see LICENSE
TwelveTake Studios LLC Website: twelvetake.com Contact: contact@twelvetake.com