Skip to main content
Glama

reaper-mcp

An MCP server that gives Claude Code (or any MCP client) full control of Reaper.

Claude can:

  • List every VST/VST3/CLAP/JS/AU plugin you have scanned

  • Add plugins to tracks, set parameters, and pick presets

  • Move volume faders, pan, mute, solo (track and master)

  • Write automation envelopes (track volume/pan or any FX parameter)

  • Set up track sends / routing

  • Create/rename/delete tracks; create/delete media & MIDI items and write MIDI notes (one at a time or a whole part in one batch call)

  • Insert existing media files — audio samples/loops or .mid clips — onto a track from disk

  • Add markers and regions; set the time selection and toggle looping

  • Arm tracks and drive the transport (play / stop / record)

  • Render the project using the last-used render settings

  • Trigger any Reaper action by command ID (escape hatch)

All 55 tools are namespaced with a reaper_ prefix (e.g. reaper_create_track) so they don't collide with other MCP servers. Read tools accept a response_format argument (markdown for humans, json for machines).

How it works

Claude Code  ──stdio──▶  reaper-mcp server  ──TCP 127.0.0.1:8765──▶  Reaper bridge ReaScript
   (MCP)                  (this package)                              (runs inside Reaper)

The bridge is a Python ReaScript that lives inside Reaper. It opens a non-blocking TCP listener and polls it from reaper.defer so the DAW UI never freezes. Every mutation is wrapped in Undo_BeginBlock / Undo_EndBlock, so anything Claude does is a single undo step.

Related MCP server: reaper-mcp-server

Prerequisites

  • Reaper installed (default location: C:\Program Files\REAPER (x64)\)

  • Python ReaScript enabled in Reaper. Open Options → Preferences → Plug-ins → ReaScript and point "Custom path to Python dll" at your Python install (e.g. C:\Users\<you>\AppData\Local\Programs\Python\Python311\). Restart Reaper. The page should say Python loaded successfully.

  • Python 3.10+ on your host machine for the MCP server itself.

Install

cd "C:\Users\tommy\Desktop\CODING STUFF\reaper-mcp"
py -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -e .

Launch the bridge inside Reaper

  1. Copy reaper_scripts\reaper_mcp_bridge.py into %APPDATA%\REAPER\Scripts\.

  2. In Reaper: Actions → Show action list → ReaScript: Load → pick the file → Run.

  3. You should see [reaper-mcp] bridge listening on 127.0.0.1:8765 in the ReaScript console.

Optional: in the action list, right-click the loaded action and "Add to toolbar", so you can start the bridge with one click. To make it auto-start with Reaper, install SWS Extension and use SWS: Set startup action.

Wire it up to Claude Code

Add to your Claude Code MCP config (%APPDATA%\Claude\claude_desktop_config.json for Claude Desktop, or ~/.claude.json / project settings for Claude Code):

{
  "mcpServers": {
    "reaper": {
      "command": "C:\\Users\\tommy\\Desktop\\CODING STUFF\\reaper-mcp\\.venv\\Scripts\\python.exe",
      "args": ["-m", "reaper_mcp.server"]
    }
  }
}

Restart Claude Code. Verify with the reaper_ping tool — it should return Reaper's version.

Try it

Ask Claude things like:

  • "List every synth I have installed." → reaper_list_installed_fx filtered to instruments

  • "Make a new track called 'Bass', drop Serum on it, and switch to the first preset." → reaper_create_track → reaper_add_fx_to_track → reaper_list_fx_presets → reaper_set_fx_preset

  • "Automate the volume of track 1 to fade in over the first 4 seconds." → reaper_add_envelope_point × 2

  • "Send track 2 to a reverb bus and pull the send down 6 dB." → reaper_add_send → reaper_set_send_volume_db

  • "Drop a 2-bar MIDI clip on track 3 and write a C major chord." → reaper_insert_midi_item → reaper_add_midi_notes (all 3 notes in one call)

  • "Mark the chorus at 32 seconds." → reaper_add_marker

  • "Arm track 1 and start recording." → reaper_set_track_record_arm → reaper_transport_record

Configuration

Env var

Default

Effect

REAPER_MCP_HOST

127.0.0.1

Where the MCP server looks for the bridge

REAPER_MCP_PORT

8765

Bridge TCP port (set on both sides if you change it)

Troubleshooting

  • could not reach Reaper bridge — the bridge script isn't running. Re-load it via the action list. Check Reaper's ReaScript console for errors.

  • Python ReaScript not loaded in Reaper — point Preferences → Plug-ins → ReaScript at a Python install of the same bitness (Python 3.x x64 for Reaper x64) and restart.

  • could not add FX 'X' (not found?) — call reaper_list_installed_fx and copy the exact name (including the VST3: / VST3i: prefix). Reaper matches by exact suffix.

  • Preset name doesn't match — some plugins expose presets as .fxp files in %APPDATA%\REAPER\presets\vst-<plugin>\. Call reaper_list_fx_presets to see what Reaper actually sees.

  • Automation doesn't seem to do anything — set the track to read mode: reaper_set_track_automation_mode(idx, "read").

Adding new capabilities

To add a tool:

  1. Write an h_<method> handler in reaper_scripts/reaper_mcp_bridge.py and register it in HANDLERS.

  2. Add a @mcp.tool(name="reaper_<verb_noun>", annotations={...}) wrapper in reaper_mcp/server.py that calls _call("<method>", ...). Validate inputs with Annotated[type, Field(...)] and Enum types, give read tools a response_format argument, and let failures raise (do not return an error dict — _call raises so FastMCP reports it as an isError result).

  3. Re-load the bridge script in Reaper (Actions list → ReaScript: Load) and restart the MCP server in Claude Code.

The method-name string is the contract between the two files and must match exactly on both sides.

Evaluations

evaluations/reaper_eval.xml holds read-only eval questions (mcp-builder Phase 4) for checking that an LLM can drive the server. See evaluations/README.md for how to run them and verify answers against a live project.

Available Tools

53 tools
reaper_add_envelope_pointA

Insert one automation point on a track volume/pan or FX-parameter envelope.

Tip: if the envelope can't be obtained, set the track to read mode first via reaper_set_track_automation_mode(track_index, 'read').

Inputs: track_index (required), target (required), time_sec (required), value (required), +4 more.

reaper_add_fx_to_trackA

Add an FX to the end of a track's chain.

Returns {track_index, fx_index, name}. If the plugin can't be found the call fails — re-check the exact string via reaper_list_installed_fx.

Inputs: track_index (required), fx_name (required), show_ui.

reaper_add_markerA

Add a project marker at a time. Returns {id, is_region, position_sec}.

Inputs: position_sec (required), name.

reaper_add_midi_noteB

Insert a single MIDI note into an existing MIDI item on a track.

Inputs: track_index (required), item_index (required), pitch (required), start_sec (required), +3 more.

reaper_add_regionA

Add a project region spanning [start, end] seconds. Returns {id, is_region, position_sec}.

Inputs: start_sec (required), end_sec (required), name.

reaper_add_sendA

Create a send from one track to another. Returns the new send's index.

Inputs: src_track_index (required), dest_track_index (required).

reaper_analyze_mixA
Read-onlyIdempotent

Analyze a rendered mix: local DSP measurements + AI listening feedback.

Two layers. Local DSP (numpy/pyloudnorm) measures the trustworthy numbers — integrated LUFS, loudness range, sample peak, crest factor, clipped samples, per-band frequency balance, and stereo correlation/width/balance. Then (unless include_ai=false) Gemini is given BOTH the audio file and those measurements and returns grounded mix/master feedback with concrete REAPER fixes.

Requires the optional deps: pip install -e .[analyze], and GEMINI_API_KEY in the environment for the AI layer. Pass a reference_path to compare against a pro track.

This reads files and calls an external API; it never modifies the Reaper project.

Inputs: audio_path (required), focus, reference_path, include_ai, +2 more. Returns: result

reaper_analyze_projectA
Idempotent

One-call mix check: quick-export the master mix, then analyze it.

This is the convenient path — no need to pre-configure the render dialog or pass a file. It tells Reaper to render the master mix to a temp file (reusing your project's render codec, e.g. WAV), measures it with local DSP (LUFS, peak, crest, per-band balance, stereo width), then — unless include_ai=false — uploads a small compressed proxy plus those measurements to Gemini for grounded feedback.

Requires the optional deps (pip install -e .[analyze]) and GEMINI_API_KEY for the AI layer. For best results set the project's render source to 'Master mix' and format to a single audio file. Writes a temp render but does not modify the project.

Inputs: focus, reference_path, bounds, include_ai, +2 more. Returns: result

reaper_clear_envelopeA
DestructiveIdempotent

Delete every point on an envelope. Same target semantics as reaper_add_envelope_point.

Inputs: track_index (required), target (required), fx_index, param.

reaper_clear_time_selectionA
Idempotent

Clear the project time selection.

Inputs: no named parameters.

reaper_create_trackA

Insert a new track. Returns the new track's state including its assigned index.

Inputs: name, position.

reaper_delete_itemA
Destructive

Delete a media/MIDI item from a track. Later item indices shift down by one.

Inputs: track_index (required), item_index (required).

reaper_delete_markerA
DestructiveIdempotent

Delete a project marker or region by its id.

Inputs: marker_id (required), is_region.

reaper_delete_trackA
Destructive

Delete the track at the given index. This is destructive and shifts later indices down by one.

Inputs: track_index (required).

reaper_get_master_trackA
Read-onlyIdempotent

Return the master track's volume (dB), pan, mute state, and FX count.

Inputs: response_format. Returns: result

reaper_get_project_infoA
Read-onlyIdempotent

Return the current project's name, length, tempo, cursor position, transport state, and track count.

Returns a dict: {name, length_sec, tempo_bpm, cursor_sec, playing, paused, recording, track_count}.

Inputs: response_format. Returns: result

reaper_get_track_stateA
Read-onlyIdempotent

Return name, volume (dB), pan, mute/solo/arm, and FX count for a single track.

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

reaper_goto_markerA
Idempotent

Move the edit cursor to a marker by its id.

Inputs: marker_id (required).

reaper_insert_midi_itemA

Create an empty MIDI item on a track spanning [start, end] seconds.

Returns {item_index, position_sec, length_sec}. Add notes with reaper_add_midi_note.

Inputs: track_index (required), start_sec (required), end_sec (required).

reaper_list_fx_paramsA
Read-onlyIdempotent

List an FX's parameters with current value, min, and max.

Returns a list of {index, name, value, min, max}. Parameter values are plugin-native (often normalised 0..1) — read min/max before setting.

Inputs: track_index (required), fx_index (required), response_format. Returns: result

reaper_list_fx_presetsA
Read-onlyIdempotent

List every preset available for an FX instance, plus the current selection.

Returns {count, current_index, presets:[{index, name}]}.

Inputs: track_index (required), fx_index (required), response_format. Returns: result

reaper_list_installed_fxA
Read-onlyIdempotent

List every FX plugin Reaper has scanned (VST2/VST3/CLAP/JS).

Reads Reaper's own scan-cache files directly (no bridge round-trip). Use this to find the exact fx_name string to pass to reaper_add_fx_to_track.

Each item: name (pass this to add_fx, e.g. "VST3i: Serum (Xfer Records)"), kind (VST/VSTi/VST3/VST3i/CLAP/CLAPi/JS), is_instrument (bool), filename.

Result is paginated. The response wraps the page in {total, count, offset, has_more, next_offset, items}.

Inputs: name_filter, instruments_only, limit, offset, +1 more. Returns: result

reaper_list_itemsA
Read-onlyIdempotent

List the media/MIDI items on a track.

Each entry: {index, position_sec, length_sec, muted, take_name}. Item index is 0-based within the track and is what the item tools expect.

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

reaper_list_markersA
Read-onlyIdempotent

List all project markers and regions.

Each entry: {index, is_region, position_sec, region_end_sec, name, id}. id is the marker/region's displayed number — pass it to delete/goto tools.

Known limitation: name may come back empty even when a marker has a name. REAPER's Python ReaScript build does not marshal the name out-parameter of EnumProjectMarkers, so names set via reaper_add_marker/reaper_add_region show in Reaper's UI but can't be read back here. Identify markers by position/id.

Inputs: response_format. Returns: result

reaper_list_sendsA
Read-onlyIdempotent

List the sends originating from a track.

Each entry: {send_index, dest_track_index, dest_track_name, volume_db, pan, muted}.

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

reaper_list_track_fxA
Read-onlyIdempotent

List FX on a track with each FX's index, name, current preset, enabled state, and param count.

FX index is 0-based within the track's chain and is what the other FX tools expect.

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

reaper_list_tracksA
Read-onlyIdempotent

List all tracks with index, name, volume (dB), pan, mute/solo/arm state, and FX count.

Track index is 0-based and is the value every other track tool expects.

Inputs: response_format. Returns: result

reaper_pingA
Read-onlyIdempotent

Check that the Reaper bridge is alive and report Reaper's version.

Call this first when anything fails — a clean response confirms both the MCP server and the in-Reaper bridge script are running and reachable.

Returns: {pong: bool, reaper_version: str}.

Inputs: response_format. Returns: result

reaper_remove_fxA
Destructive

Remove an FX from a track's chain. Indices of later FX shift down by one.

Inputs: track_index (required), fx_index (required).

reaper_remove_sendA
Destructive

Remove a send from a track. Later send indices shift down by one.

Inputs: track_index (required), send_index (required).

reaper_rename_trackA
Idempotent

Rename a track. Returns the updated track state.

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

reaper_render_projectA

Render the project to disk using Reaper's most recent render settings.

This reuses whatever output path, bounds, and format were last configured in Reaper's Render dialog — set those up once manually first. Writes a file but does not modify the project.

Inputs: no named parameters.

reaper_run_actionA
Destructive

Trigger any Reaper action by numeric command ID (Main_OnCommand).

The escape hatch for actions not yet wrapped as dedicated tools. Look up IDs in Reaper's Actions list (right-click an action → Copy selected action command ID). Marked destructive because arbitrary actions can do anything.

Inputs: command_id (required).

reaper_set_cursorA
Idempotent

Move the edit cursor to a time in seconds. Returns the resulting cursor position.

Inputs: time_sec (required), move_view.

reaper_set_fx_enabledA
Idempotent

Enable or bypass an FX (enabled=False bypasses it without removing it).

Inputs: track_index (required), fx_index (required), enabled (required).

reaper_set_fx_paramA
Idempotent

Set an FX parameter by index or name. Returns {param_index, value, min, max}.

Inputs: track_index (required), fx_index (required), param (required), value (required).

reaper_set_fx_presetA
Idempotent

Switch an FX to a preset by name or by index.

Provide exactly one of preset_name or preset_index. Use reaper_list_fx_presets to discover valid values.

Inputs: track_index (required), fx_index (required), preset_name, preset_index.

reaper_set_loop_enabledA
Idempotent

Enable or disable looped playback (repeat over the time selection).

Inputs: enabled (required).

reaper_set_master_volume_dbA
Idempotent

Set the master track's volume fader in dB.

Inputs: db (required).

reaper_set_send_volume_dbA
Idempotent

Set the level of a track send in dB.

Inputs: track_index (required), send_index (required), db (required).

reaper_set_tempoA
Idempotent

Set the project tempo in BPM. Returns the resulting tempo.

Inputs: bpm (required).

reaper_set_time_selectionA
Idempotent

Set the project time selection (the loop/render range) to [start, end] seconds.

Inputs: start_sec (required), end_sec (required).

reaper_set_track_automation_modeA
Idempotent

Set a track's automation mode (trim/read/touch/write/latch/latch_preview).

Set to 'read' for written envelopes to play back.

Inputs: track_index (required), mode (required).

reaper_set_track_muteA
Idempotent

Mute or unmute a track. Returns the updated track state.

Inputs: track_index (required), mute (required).

reaper_set_track_panA
Idempotent

Set a track's pan. Returns the updated track state.

Inputs: track_index (required), pan (required).

reaper_set_track_record_armA
Idempotent

Arm or disarm a track for recording. Returns the updated track state.

Inputs: track_index (required), armed (required).

reaper_set_track_record_inputA
Idempotent

Set a track's record input (audio channel or encoded MIDI input).

Inputs: track_index (required), input (required).

reaper_set_track_soloA
Idempotent

Solo or un-solo a track. Returns the updated track state.

Inputs: track_index (required), solo (required).

reaper_set_track_volume_dbA
Idempotent

Set a track's volume fader in dB. Returns the updated track state.

Inputs: track_index (required), db (required).

reaper_transport_pauseA
Idempotent

Pause the transport, keeping the cursor where it is.

Inputs: no named parameters.

reaper_transport_playA
Idempotent

Start playback from the edit cursor.

Inputs: no named parameters.

reaper_transport_recordA

Start recording on all armed tracks.

Inputs: no named parameters.

reaper_transport_stopA
Idempotent

Stop the transport.

If Reaper is recording, the call is refused unless force=true — this avoids ending a take without the user's go-ahead. Ask the user first, then retry with force=true.

Inputs: force.

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    A4/5.0

    Scored across 53 tools

    Disambiguation5/5

    Each tool has a clear, distinct purpose. Even similar tools like reaper_add_marker and reaper_add_region are differentiated by region spanning a range. Descriptions provide enough detail to avoid confusion.

    Naming Consistency5/5

    All tools follow the verb_noun pattern with 'reaper_' prefix. Naming is perfectly consistent across the entire set.

    Tool Count4/5

    53 tools is high but justified for a DAW control server covering many aspects (tracks, FX, sends, automation, transport, etc.). It's slightly above the ideal range but still well-scoped without redundancy.

    Completeness4/5

    Covers most core DAW operations: track management, FX, sends, automation, MIDI, markers, transport, analysis, render. Minor gaps like item editing (split, move) or detailed MIDI editing are missing but not critical for basic workflows.

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      A Model Context Protocol server that exposes REAPER digital audio workstation functionality through a clean API interface, enabling programmatic control of 169+ REAPER operations across track management, MIDI editing, effects, automation and more.
      88
      MIT
    • F
      license
      Not graded
      quality
      D
      maintenance
      MCP server for controlling Renoise via OSC. Lets Claude compose music by writing patterns, triggering notes, and controlling playback.
      4
      -
    • A
      license
      B
      quality
      D
      maintenance
      This MCP server enables AI assistants to control a live REAPER DAW instance, including transport, tracks, FX, MIDI, media, markers, rendering, and project state, with an escape hatch for arbitrary ReaScript commands.
      40
      MIT