reaper-mcp
One-line summary: reaper-mcp is an MCP server that lets an agent inspect and fully edit a running REAPER project over a Lua bridge — tracks, MIDI, FX, sends, items, automation, rendering and arbitrary ReaScript.
Inspect the session with
status: tempo, play state, cursor, tracks/selection, time selection, selected items, solo/mute/dirty, plus optional arrangement facts (time signature, tempo map, length, markers, MIDI vs audio).Control transport: play, stop, pause, record, toggle repeat, jump to start or to a beat/marker/region.
Manage tracks: list, add, delete, rename, set volume/pan/mute/solo, and build submix buses that reroute sources.
Edit MIDI: create items, add/replace/update/delete notes, and insert CC, program changes and pitch bend.
Work with FX: list, add, delete, bypass, reorder, load presets, inspect parameters (with name filter) and set values either normalized or as displayed (
formatted).Route sends: add/update/delete sends with volume, pan, mute, pre/post-fader/pre-FX mode, and channel-pair routing for sidechains.
Arrange media items: list, import from host paths, split, delete, duplicate, move, trim edges, fades and shapes, take selection.
Automate envelopes: list, read and write points (whole or by beat range), in gain or dB.
Edit project level: tempo, time signature, time selection, markers/regions, and save without a dialog.
Render audio: master mix, time selection, custom range or stems; WAV (16/24/32f) or MP3; loudness/peak measurement, with warnings and solo/file-overwrite guards.
Escape hatches: run any REAPER action by command id, call any ReaScript function by name, or execute arbitrary Lua inside REAPER with a timeout.
Batch everything: many calls in one IPC hop and one undo point, with optional stop-on-error.
Every mutating call becomes a single labelled undo point, so edits stay reversible.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@reaper-mcp Render the project to MP3"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Hibiki
Hibiki is the agent inside your music editor, built for professionals. Talk to it about what you're working on, let it edit, arrange and mix alongside you, and bring the AI agents you already use. It runs in REAPER today.
Path | What |
| MCP server ( |
| Hibiki — chat panel docked in REAPER (ReaImGui) for Gamut, Codex and other ACP agents |
| Starts the bridge and the chat panel whenever REAPER launches |
| Agent gateway: one local API for the panel in front of Gamut and ACP agents (Codex, …) |
| Remote-host bootstrap (Cloudflare Tunnel) and hot-swap deploy of the bridge — see |
MCP client --stdio JSON-RPC--> reaper_mcp/server.py --JSON mailbox--> reaper_mcp/bridge.lua (inside REAPER)Fourteen grouped tools. Multi-step edits go through batch; anything else through reaper_call / run_lua. Track index -1 is the master. Time is project quarter notes. Call status first; on a new project pass detail=true for arrangement facts (time signature, length in beats, markers, MIDI vs audio) — not chords. midi cc is CC and program change; item import takes a path on the REAPER host; project save writes without a dialog (pass path if the project is unsaved). midi get omits default fields; batch slots are the inner result or {error}.
Just want the MCP? For Claude Desktop, Claude Code or Cursor with no panel, no gateway and no background services, see MCP only.
Install (macOS)
REAPER first. Download it from reaper.fm, drag it to Applications and open it once. The package (and
hibiki setup) refuses to install on a Mac without REAPER.Hibiki. Download
Hibiki-<version>.pkgfrom Releases and open it. The package brings its own Python, so it doesn't need the Xcode command line tools. To upgrade, install a newer package.Restart REAPER. The Hibiki panel opens docked on the right; click the agent name at its top to pick a provider and model.
Connect an agent — Gamut or a CLI agent: see Connect an agent.
The package isn't signed yet. If macOS says it can't verify the developer, open System Settings → Privacy & Security and click Open Anyway.
What it sets up for the logged-in user (hibiki setup runs the same steps; safe to re-run):
Piece | Where |
Lua bridge, Hibiki panel |
|
ReaImGui (if missing, pinned + sha256-checked), and its |
|
Startup hook: starts both with REAPER | a marked block in |
MCP over HTTP on | LaunchAgent |
Agent gateway on | LaunchAgent |
MCP registration | Gamut (as REAPER), plus Claude Desktop, Claude Code and Cursor when they're installed |
hibiki doctor # what's installed, what's running, what's wrong
hibiki recover # restart the MCP + gateway, drop stuck panel streams (REAPER untouched)
hibiki connect gamut|claude-desktop|claude-code|cursor [--remove]
hibiki agents add codex claude kimi # ACP agents for the panel (Node goes in ~/.local/node)
hibiki watchdog on|off # relaunch REAPER after crashes, for an unattended Mac
hibiki stop # turn the background services off; they stay off after login
hibiki start # turn them back on (setup does too)
hibiki update # newer release on GitHub? (--channel stable|dev, --json; dev builds default to dev)
hibiki update --install # download it, verify its sha256, open the installer (you finish it); source clones: git pull
hibiki uninstall [--purge] # --purge also deletes tokens and gateway config
hibiki use dev [--path ~/reaper-mcp] # testing unreleased code: run everything from a git checkout (no admin)
hibiki use release # back to the installed package
hibiki use [status] [--json] # which one is live: release version, or checkout path @ commithibiki use dev records the checkout in ~/.config/reaper-mcp/mode.json and runs the checkout's setup with the
package's Python, so the LaunchAgents, the bridge and the panel come from the checkout; every hibiki command
(including the panel's Recover and update) then runs the checkout's code. Restart REAPER to load the new bridge and
panel. hibiki update --install refuses in dev mode, and installing a package switches back to release.
From a clone instead (the LaunchAgents then run from the clone, so keep it; re-run after git pull):
git clone https://github.com/yiw190/hibiki.git ~/hibiki
sh ~/hibiki/install.sh # WITH_AGENTS=1 also adds Codex, Claude Code and KimiRelated MCP server: reaper-reapy-mcp
Install (Windows)
Release candidate: tested in CI on Windows Server, not yet on a desktop REAPER. Windows 10 1803+ (64-bit).
REAPER first. Download the 64-bit installer from reaper.fm, install it and open REAPER once. The installer (and
hibiki setup) refuses to install on a PC without REAPER.Hibiki. Download
Hibiki-<version>-setup.exefrom Releases and run it. It installs for your Windows user only (%LOCALAPPDATA%\Programs\Hibiki, no administrator rights), brings its own Python and addshibikito your PATH. To upgrade, run a newer installer; to remove, use Settings → Apps.Restart REAPER. Same as on macOS: the panel opens docked on the right.
Connect an agent — see Connect an agent.
The installer isn't signed yet: if SmartScreen stops it, click More info → Run anyway.
Differences from macOS: the REAPER resource path is %APPDATA%\REAPER; instead of LaunchAgents one background
supervisor (hibiki run, windowless) keeps the MCP and the gateway running, started at logon from
HKCU\...\CurrentVersion\Run; logs are in %LOCALAPPDATA%\Hibiki\logs; Open in Claude Code / Kimi opens a
cmd window; the watchdog is macOS only. From a clone: py -m reaper_mcp setup (Python 3.9+).
Connect an agent (step 4)
The panel talks to an agent; Hibiki doesn't ship one. Pick either route — or both, they show up side by side in the panel's Agent settings → Provider.
Route A — Gamut (desktop app, agents with skills, dashboards, connected accounts):
Download Gamut — macOS (Apple Silicon) · Windows · all releases (source, gamut.so).
Open it and sign in with your Gamut account. Gamut sets up its own agent containers and models; your own API keys (Anthropic, OpenRouter, Bedrock, OpenAI) are optional.
Create an agent.
In the Hibiki panel pick Gamut and the agent under Agent details. Gamut gives MCP servers to agents one by one, so the panel offers Enable REAPER for until that agent has it (one click; it also registers the MCP in Gamut if setup ran before Gamut was installed). From a terminal instead:
hibiki connect gamut --agent "<name>"(or--all-agents, or no flag to pick from a list).
Route B — a coding-agent CLI (each uses its own login / subscription): click Install next to it on the panel's
"Connect an agent" card or in Agent settings → Provider — it installs Node and the CLI into ~/.local/node (no admin
rights) and loads it without a restart — then Connect to log in once. The REAPER MCP is wired in automatically.
Agent | Package | Login |
Claude Code |
| your Claude login |
Codex |
| ChatGPT / OpenAI |
Kimi |
| kimi.ai or kimi.com (one button each) |
MiniMax |
| global or mainland account (one button each) |
Grok |
| browser sign-in; SuperGrok or X Premium+ (beta) |
Gemini |
| Google sign-in in the browser; Google AI Pro / Ultra |
Copilot |
|
|
Same from a terminal: hibiki agents add claude kimi minimax grok gemini copilot codex. Not one-click yet: Qwen Code (ACP only offers
an OpenAI-compatible API key set through environment variables) and DeepSeek (its harness's ACP server is
automation-only; DeepSeek models work through an ACP agent such as OpenCode with an API key).
MCP only
On macOS or Windows, from a clone:
git clone https://github.com/yiw190/hibiki.git ~/hibiki
sh ~/hibiki/install.sh --mcp-only # Windows: python -m reaper_mcp setup --mcp-onlyWhat it does:
Installs the bridge and a startup hook that starts it with REAPER.
Registers the MCP in Claude Desktop, Claude Code and Cursor, if they're installed.
Nothing else: no panel, no background services, no token.
Keep the cloned folder: those apps run reaper_mcp/server.py from it. Check the install with
hibiki doctor --mcp-only.
Gamut needs the full install instead: it reaches REAPER through the background HTTP service, which this mode leaves out.
For other MCP clients or operating systems, see the next section.
Manual setup (any MCP client, any OS)
python3 -m reaper_mcp install-bridgeThen in REAPER: Actions → Load ReaScript → reaper_mcp_bridge.lua → Run. It starts silently (no console window); hibiki doctor shows the bridge version and heartbeat. Set REAPER_MCP_DEBUG=1 to log to the ReaScript console.
MCP client config (any client that runs stdio servers):
{
"mcpServers": {
"reaper": {
"command": "python3",
"args": ["/absolute/path/to/hibiki/reaper_mcp/server.py"]
}
}
}On Windows use native Python, not WSL (they don't share the mailbox).
REAPER_MCP_IPC_DIR mailbox override (must match on both sides)
REAPER_MCP_TIMEOUT default 10s
REAPER_MCP_DEBUG=1 Lua request logMailbox: ~/Library/Application Support/reaper-mcp/ipc on macOS, %APPDATA%/reaper-mcp/ipc on Windows,
$XDG_DATA_HOME/reaper-mcp/ipc on Linux. Time is beats. Indices are 0-based.
Hibiki panel (macOS, Windows)
Needs ReaImGui ≥ 0.10 and an agent: Gamut or one of the CLI agents (see
Connect an agent). The panel talks to the agent gateway
on 127.0.0.1:47892; for Gamut it uses the desktop app's local REST + SSE API (127.0.0.1:47891), the same one
Gamut's own UI uses.
The installer puts it in place. By hand: 1. Copy panel/Hibiki.lua, panel/context.lua, panel/markdown.lua and panel/studio.lua to <REAPER resource path>/Scripts/Hibiki/
(and panel/Hibiki_Meter.jsfx to <REAPER resource path>/Effects/Hibiki/), then Actions → Load ReaScript and run Hibiki.lua.
2. Optional: run panel/restart_apply.sh while REAPER is open and quit REAPER — it docks the panel on the right,
binds Cmd+L to toggle it, and relaunches REAPER.
What it does: the header shows the agent and the model in effect (Gamut, Claude Code, Kimi, …); click it for
Agent settings, a Routing-style window with the provider, the Gamut agent, model / effort / mode, the context
switch and the live REAPER selections; the clock lists recent chats, + starts one. For Claude Code and Kimi,
Open in … reopens the chat in the agent's own CLI in Terminal. Replies stream with a markdown renderer; tool calls
collapse into one line per run. Every message carries a [REAPER context] block: project, tempo, cursor and nearby
markers, then each selection kind — time selection, razor areas, tracks, items, MIDI notes, envelope, FX — with how
long ago it was set and, for time/razor ranges, the chord markers and what plays there. Pills above the input show
the same selections, newest first. Enter sends, Shift+Enter is a newline. Drag to select message text and Cmd+C to
copy. Attach files with + File or by dropping them on the panel: they're uploaded to the agent (Gamut's
upload-file; for ACP agents the gateway stores them and sends images as image blocks) and listed in the message as
[Attached files:] (for Gamut, whose copies live in the agent's container, followed by the files' paths on the
REAPER host, which item import needs). A Gamut agent's questions, secrets, script runs and approvals are answered in
the panel; connecting an account or MCP server, uploading a requested file, a browser step or computer use opens that
chat in Gamut (superagent://agent/<slug>/sessions/<id>). Scrolling follows Gamut's own follow engine. Chinese/Japanese IME:
ReaImGui passes keys to both the IME and ImGui, so the panel undoes ImGui's half of Backspace / arrows / Esc / Enter
while a composition is open and shows the pending pinyin under the input.
Gamut's local API has no auth in desktop mode and listens on all interfaces. Block port 47891 in the macOS firewall if the Mac is on a network you don't trust.
Around the chat (panel/studio.lua)
Version history. After every agent reply that changed the project, a copy of it (saved or not;
Main_SaveProjectExto another path leaves the open project's path and dirty state alone) goes to<project folder>/.hibiki/history/<name>/<stamp>.RPP.gzwith a line inindex.jsonl: about 40 KB each, no media, the newest 200 kept. Each version is titled with the reply's own first sentence; hover lists what changed. The bridge knows what changed because it runs every request that can change the project in one undo block labelledHibiki <reply>: <what changed>and lists the changes in ExtStateHibiki/receipts; forrun_luaand raw API calls it diffs the project before and after (tracks, volume, pan, mute, FX added / removed / bypassed / offline, items, lanes, sends, tempo), and a first-line-- commenttitles the script. Agent settings → Version history: Current (with Save version when it isn't in the history yet), then the 10 newest versions with the time to the second and Go to, which saves Current as a version first, then makes this tab that version.Measure playback.
Hibiki_Meter.jsfxsits on the master's monitoring FX (never rendered) and writes a frame every 100 ms of playback to gmemHibiki: LUFS-M/S (BS.1770 K-weighting), 4× oversampled true peak, sample peak, correlation, side vs mid and eight mid bands. The next message's context gets the last playback: bars, gated LUFS-I, the loudest LUFS-S and true peak with their bar.beat, correlation minimum, band levels and a per-bar LUFS-M / true-peak row. Switch it in Agent settings → Context → Measure playback.Audition rack. An agent offers audible alternatives (sounds, parts, effects; not levels) preferably as fixed lanes of one track tagged
P_EXT:hibiki_lanes = "<group>"(one lane playing, lane names as labels), or by tagging tracksP_EXT:hibiki_var = "<group>/<n>"(one unmuted) or FX on one track withP_EXT:hibiki_fxvarlines"<group>/<n>\t<fx GUID>"(one enabled). The panel shows a row of numbered buttons per group above the input with the playing variant's name. Click or press 1–9 (panel focused) to switch (no undo point); when stopped, a click also loops the time selection, which the agent sets to the section where the variants differ, so a click is a listen. Hover = the loudness each variant measured while it played. Keep n deletes the other variants and their tags in one undo step.Ears. With a time selection or razor area, Ears renders it from the master (≤ 30 s, 24-bit WAV in the panel's private folder, your render settings restored afterwards), reads REAPER's LUFS-I / LUFS-S max / true peak, runs
hibiki ears(stdlib spectrum: 1/3-octave mid and side, tilt, bands over/under the tilt, stereo, level over time →.png+.md) and attaches the picture, the summary and the audio to your next message.Agent rules.
/remember <rule>saves a line to yourrules.md(/remember off: <id>switches a convention off). Agent settings → Context → Agent rules showsN defaults (M off) · K yours; Edit opensdefaults.mdandrules.md. See Rules for agents.
Rules for agents
Every agent gets one text: Hibiki conventions from your defaults.md followed by your rules from
rules.md, both in ~/.config/hibiki/brain/ (HIBIKI_BRAIN overrides the folder; the same path on Windows, under
your profile).
defaults.mdstarts as a copy of the shippedbrain/defaults.md(general know-how such as one DLSMusicDevice per project, never rendering onto an existing file), made byhibiki setupor the first read. It is yours: rewrite or delete any rule. Rules are bullets with a stable id,- [single-dls] ....On every install or upgrade,
hibiki setupmerges the new shipped file in per id: a rule you left untouched gets the new text, one you edited keeps your wording, one you deleted stays deleted, a new id is added at the end; lines without an id are never touched (brain/.defaults-state.jsonremembers what was last shipped).hibiki rules reset <id>(or--all) brings the shipped text back.rules.mdis free text, one rule per line (/remember <rule>in the panel adds one). It also understandsoff: <id>(leave a default out) and[<id>] <text>(replace its text), but editingdefaults.mdis simpler.<!-- comments -->are not sent.Delivered two ways: the MCP server appends the composed text to its
initializeinstructions (read at every session start, so edits apply to the next chat without a restart; Gamut agents and any MCP client see it), and the gateway writes it intoAGENTS.md,CLAUDE.mdandGEMINI.mdin the ACP agents' working folder (a marked block; your own text in those files stays) before each new chat. Capped at 12,000 characters.hibiki rulesprints what agents get,hibiki rules --paththe rules.md path,hibiki rules edit [defaults|mine]opens both files (or one),hibiki rules off <id>/on <id>toggle a default from rules.md. The panel's Agent rules → Edit opens both files.
Start with REAPER
The installer merges reaper/__startup.lua into <REAPER resource path>/Scripts/__startup.lua as a marked block. It starts the
MCP bridge and opens the chat panel on every launch, registering either script if REAPER doesn't know it yet.
Agent gateway: Codex, Claude Code, Kimi, … in the same panel
gateway/agent_gateway.py is a small local server (127.0.0.1:47892, stdlib Python) that the panel talks to first.
It proxies Gamut agents unchanged and adds ACP agents — Codex via
@agentclientprotocol/codex-acp, Claude Code via @agentclientprotocol/claude-agent-acp, Kimi Code CLI (kimi acp),
and anything else that speaks ACP — under the same API. Subscriptions work: Codex logs in with ChatGPT, Claude Code
reuses the local claude login, Kimi's login button opens kimi login (device code) in Terminal. An agent's
loginVariants turn its terminal login into one button per variant, each appending its args to the login
command (the Kimi entry ships kimi.ai = --region global and kimi.com = --region mainland-cn). Each ACP session gets this
repo's MCP server, so every backend can drive REAPER. The panel shows model / effort / mode pickers for both kinds
(Gamut's model catalog, ACP config options), permission buttons when an ACP agent asks before a tool call, and a
login button when the agent needs one. If the gateway isn't running the panel falls back to Gamut directly.
Every request except /health needs Authorization: Bearer <token> from ~/.config/agent-gateway/token (created
with mode 0600 on first start; the panel reads it). Docker and Lima forward host.docker.internal /
host.lima.internal to the Mac's loopback, so without the token any container on the Mac could start a host agent.
hibiki agents add codex claude kimi # Node (~/.local/node) + the ACP adapters, restarts the gateway
python3 gateway/test_gateway.py # fake Gamut + fake ACP agent, no networkAgents are listed in ~/.config/agent-gateway/config.json (acp: [{slug, name, command, env, cwd}],
mcpServers: [...]). Transcripts of ACP sessions are kept in ~/.config/agent-gateway/sessions/.
hibiki agents add installs each adapter at a pinned npm version with install scripts off (MiniMax keeps them: its
SQLite binding and ripgrep are fetched by them).
An ACP agent starts on first use (a message, its config, or /status?probe=<slug>; probe=1 only checks that the
binary is there and returns the last-known login state). After 10 minutes with no running turn and no open stream
(AGENT_GATEWAY_IDLE, seconds) the gateway stops it and the MCP servers it started; the next message restarts it and
reloads the chat.
Gamut desktop on the same Mac: install.sh registers the MCP as http://localhost:8787/mcp (no tunnel). Agent running somewhere
else and need to reach REAPER over the internet? See docs/remote-host.md.
Troubleshooting
hibiki recover (also the Recover button in the panel's settings) restarts the MCP front and the gateway (their
ACP agents go with it), kills leftover panel stream curls, puts back a missing bridge script / panel / token, waits
up to 10 s for both services and reports the bridge heartbeat. It never touches REAPER: a stale heartbeat means
REAPER is busy or hung, and the watchdog restarts a hung one. --json prints {"ok", "steps": [{"name", "ok", "detail"}]}; exit 0 when the MCP and the gateway answer. hibiki doctor lists everything else.
Security notes
The HTTP front (
127.0.0.1:8787) refuses to start with a bearer shorter than 32 characters;hibiki setupandscripts/macos-host-bootstrap.shgenerate one with a CSPRNG when none is given.Exposed through a Cloudflare tunnel, the bearer is the only gate in front of
run_lua, i.e. a shell on the Mac. Only run the tunnel while an agent outside the Mac needs it, and put a Cloudflare Access policy (service token or identity) in front of the tunnel hostname so requests are filtered before they reach the Mac.
Tools
status transport track midi fx send item envelope project render action reaper_call run_lua batch
Behaviour worth knowing (all optional parameters; older calls work unchanged):
statusalso returnsany_solo(REAPER's own solo state, which can differ from a track'sI_SOLO),master_muteanddirty.renderruns action 40101 (set all media online) first (media_online=falseskips it), refuses when a target file already exists (REAPER's overwrite prompt would block the bridge) and when tracks are soloed (allow_solo=true, orsolo_indices/mute_indicesto solo/mute tracks for this render only; they are restored afterwards). It returnsfiles: [{path, bytes, length_sec, peak_db, lufs_i}]andwarnings(near-silent, file not written, master muted, stems that came out as the master).measure=falseskips the loudness scan.fx settakesformattedinstead ofvalue: the value as the plugin shows it (-18for dB,4for 4:1,inf, or a label such as3.2k). It searches the display text and returns theformattedvalue it actually set.send add|updatetakemode(post_fader/pre_fader/pre_fx) andsrc_channel/dst_channel, the first channel of a stereo pair counted from 0 (dst_channel=2= channels 3/4, a compressor's sidechain input). The destination track gets more channels if it needs them.envelope get|settakeunit=dbfor volume-type envelopes.setturns an inactive (ACT 0) envelope back on and rejects points that have novalue.run_luatakestimeout(seconds, default 10, at most 600). Errors quote the failing source line. REAPER is frozen while a snippet runs, so start long host commands in the background and poll their log.Every call that can change the project is one undo point labelled
Hibiki <reply>: <what changed>(abatchis one point for all its calls, with no rollback:stop_on_error=trueskips the rest after a failure); see Version history.A reply works on the project tab that was in front when it first changed something: if another tab comes to the front, writes and renders are refused (from the panel, until the reply ends; without the panel the first refusal re-pins to the new tab).
statusalways returnscursor_beats,time_selection, selected tracks (selected) andselected_items;detail=trueaddstempo_map(tempo and meter changes).itemarranges:split(at_beats),delete,duplicate(an unpooled copy), andupdatewithleft_edge_beats(trim the start, content stays put),dest_track_index,active_take,fade_in_sec/fade_out_secandfade_*_shape. Item indices follow position, so list again after a move.envelope get|settakestart_beats/end_beats:setthen replaces only the points in that range.transport gotomoves the edit cursor toposition_beatsor a marker/region (number or name); transport returnsposition_secandposition_beats.rendertakesformat(wavwithbit_depth16 / 24 / 32 float, ormp3at 320 kbps) for that render only.fx paramstakesfilter;midi get_ccreads CC, program and pitch bend.run_lua'stimeoutstops a snippet that is still running Lua (what it did until then stays done); a call blocked inside REAPER (ExecProcess, a render, a dialog) can't be stopped.One REAPER serves the mailbox: a second REAPER's bridge waits until the first one's heartbeat goes stale, and a request is claimed by renaming it, so it never runs twice.
Tests
python3 tests/test_server.py # MCP server + fake bridge, versions in step
uv run --with lupa python tests/test_bridge_lua.py # bridge.lua against a fake ReaScript API
uv run --with lupa python panel/test_panel.py # chat panel events, sends and cards, fake reaper/ImGui
python3 gateway/test_gateway.py # agent gateway against fake Gamut + fake ACP agent
python3 tests/test_suite.py # setup / doctor / connect / uninstall on a fake HOME
python3 tests/test_ears.py # `hibiki ears` on synthetic WAVs
uv run --with lupa python scripts/check_syntax.py # every .lua compiles under Lua 5.4, every .sh parsesCI runs all of these on every push: the Python suites on 3.9 (the macOS host's /usr/bin/python3) and 3.12.
None of these need REAPER. The Lua-based ones need lupa (CI installs it).
Contributing
See CONTRIBUTING.md. Report security issues privately: SECURITY.md.
License
MIT
Available Tools
14 toolsactionB
Run a REAPER Main_OnCommand by numeric command id.
Inputs: command_id (required).
batchA
Many operations in one IPC hop and one undo point. Each call is {func, args} or {func: 'run_lua', code, timeout} or {func, arguments} for a grouped tool name (track/midi/fx/...). Each slot is the inner result, or {error}. There is no rollback: by default one failure does not abort the rest; stop_on_error=true skips the slots after the first failure ({skipped: true}). Handles from earlier calls work later.
Inputs: calls (required), stop_on_error.
envelopeA
Track envelopes. action: list | get | set. name is REAPER envelope name (Volume, Pan, Mute, ...). set replaces all points, or with start_beats / end_beats only the points in that range (ends included; every new point must lie inside it); get with a range returns only those points. value is the envelope's value; Volume is linear gain (1.0 = 0 dB, 0.5 = -6 dB), also on fader-scaled envelopes. unit=db reads/writes volume-type envelopes (Volume, Trim Volume, send Volume) in dB. set re-activates an envelope left inactive (ACT 0).
Inputs: action (required), track_index (required), name, unit, +4 more.
fxB
Track FX. action: list | add | params | set | delete | bypass | move | preset. params takes filter (case-insensitive part of the parameter name) to list only matching ones. track_index -1 is the master. set takes value 0..1 (REAPER normalized) or formatted: the value as the plugin displays it (number in its unit, e.g. -18 for dB, 4 for 4:1, 120 for ms; or a label like "3.2k"), resolved by searching the display text. set returns the formatted value actually set.
Inputs: action (required), track_index (required), param, value, +7 more.
itemA
Media items on a track. action: list | update | import | split | delete | duplicate. Times are beats except fade_in_sec / fade_out_sec (seconds, REAPER native). update: gain_db, fades and fade_*_shape, loop, mute, position_beats (move), length_beats (trim the end), left_edge_beats (trim or extend the start; the content stays in place), dest_track_index (move to another track; returns the new indices), active_take. list shows take name, source file and take count. split cuts at at_beats (inside the item) and returns the pieces' item_indices. delete takes item_index or item_indices. duplicate copies the item (unpooled) to position_beats (default: right after it), optionally on dest_track_index. import uses a path already on the REAPER host; as_new_track=true makes new tracks. Item indices follow position, so re-list after edits that move items.
Inputs: action (required), loop, mute, path, +16 more.
midiB
MIDI on a track item. Times are absolute project beats. action: create_item | add | get | replace | update | delete | cc | get_cc. replace rewrites the whole take in one undo step; add only appends. cc inserts CC (cc+value) or program change (program) via ccs[]; get_cc reads CC, program and pitch_bend back in that shape. get omits index (use array offset), channel if 0, muted/selected if false.
Inputs: action (required), track_index (required), ccs, muted, +9 more.
projectB
Project-level edits. action: tempo | time_signature | time_selection | marker | save. save with path creates missing folders and writes a copy (no dialog); an untitled project adopts that path. save without path needs an already-named project.
Inputs: action (required), bpm, name, path, +7 more.
reaper_callB
Call any ReaScript function by name. Pointers come back as {"__handle":"hN"} and can be passed back in. Example: func=CountTracks args=[0].
Inputs: func (required), args.
renderA
Render. No undo. Long timeout. bounds: project | time_selection | custom | items. Default: the master mix. stems=true renders the selected tracks as stems instead (pass track_indices to select them). path is the output folder; the file name comes from pattern. Sets all media online (action 40101) first unless media_online=false. Refuses when a target file already exists (REAPER's overwrite prompt would hang the bridge) and when tracks are soloed (pass allow_solo=true, or solo_indices / mute_indices to solo/mute tracks for this render only; they are restored afterwards). Returns files [{path, bytes, length_sec, peak_db, lufs_i}] and warnings (near-silent, missing file, master muted); measure=false skips the loudness scan. format wav (bit_depth 16 | 24 | 32 = float) or mp3 (320 kbps) sets the file type for this render only; without it the project's render format is used.
Inputs: path, stems, bounds, format, +12 more.
run_luaA
Run a Lua snippet inside REAPER (reaper in scope). Use return to send a value. Best for multi-step work that would otherwise be many round-trips. Errors carry the failing line. timeout (seconds, default 10, max 600): a snippet still running Lua after it is stopped with an error (what it did until then stays done); a call blocked inside REAPER (ExecProcess, a render, a dialog) can't be stopped. REAPER is frozen while it runs, so start long host commands in the background (io.popen('cmd > log 2>&1 &')) and poll instead.
Inputs: code (required), timeout.
sendB
Track sends. action: list | add | delete | update. track_index is the source (-1 master). dest_index is the destination track. add/update take volume_db, pan, mute, mode (post_fader | pre_fader | pre_fx) and channel routing: src_channel / dst_channel = first channel of the stereo pair, 0-based (dst_channel 2 = channels 3/4, a compressor's sidechain input; the destination's channel count is raised to fit).
Inputs: action (required), track_index (required), pan, mode, +6 more.
statusA
Check the Lua bridge and return project tempo, play state, cursor_beats, tracks (selected=true on selected ones), time_selection {start_beats, end_beats} when there is one, selected_items [{track_index, item_index}], any_solo, master_mute and dirty (unsaved changes). Call first; clear a lingering solo before rendering. detail=true adds arrangement facts (time signature at the start, tempo_map of tempo/meter changes, length in beats, markers, MIDI vs audio per track) without guessing chords.
Inputs: detail.
trackB
Track operations. action: list | add | delete | update | bus. update uses name, volume_db, pan (-1..1), mute, solo. bus creates a submix named name and routes source_indices through it (their direct send to the master/parent is turned off).
Inputs: action (required), pan, mute, name, +4 more.
transportB
Playback control. action: play, stop, pause, record, toggle_repeat, goto_start, goto (edit cursor to position_beats, or to a marker/region by number or name; moves playback too when playing). Returns play_state, position_sec and position_beats.
Inputs: action (required), marker, position_beats.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 14 tools
Resource tools (track, item, midi, fx, envelope, send, project, transport, render) are mostly distinct, but four generic escape hatches—action, reaper_call, run_lua, and batch—all execute arbitrary commands and could easily be misselected. The descriptions offer guidance on when to use each, but the boundaries between 'run a Main_OnCommand', 'call a ReaScript function', 'run a Lua snippet', and 'batch these together' remain fuzzy.
All names are lowercase snake_case and predominantly resource-oriented nouns, which makes the set readable and predictable. Minor deviations: a few generic names (action, status, batch) and a couple of verb forms (render, run_lua) break the pure noun convention.
14 tools is within a reasonable scope for a DAW control server covering tracks, items, MIDI, FX, envelopes, sends, rendering, and project settings. The count is slightly inflated by redundant abstraction layers (action/reaper_call/run_lua/batch) that could arguably be consolidated.
Coverage is broad: arrangement state, transport, MIDI, FX, items, envelopes, sends, routing buses, project tempo/markers, rendering, and raw escape hatches. Minor gaps remain—no explicit undo/redo control, limited take management beyond active_take, and marker/region lifecycle is only partially exposed (creation via project, deletion unclear).
Maintenance
Related MCP Connectors
Remote MCP server for audio stem separation, denoise, reverb, and MIDI export.
Create, co-edit, analyze, publish, and export collaborative step-sequencer sessions through MCP.
OSC ↔ MIDI bridge for synthesizers and DAWs, with the SynthHub catalogue. A MIDI MCP and OSC MCP.
MCP registry & directory: search, find & install 31k+ MCP servers & tools. Catalog and marketplace.
Related MCP Servers
- AlicenseBqualityDmaintenanceAn MCP server that enables users to control and edit REAPER projects through a Python-based interface and a Lua bridge. It supports managing tracks, controlling transport, manipulating MIDI and audio items, and adjusting FX parameters within the digital audio workstation.57GPL 3.0
- AlicenseCqualityCmaintenanceEnables AI assistants to control REAPER DAW via the Model Context Protocol, including track, FX, MIDI, and audio operations.4790MIT
- AlicenseCqualityAmaintenanceA comprehensive MCP server that enables AI assistants to control REAPER DAW for mixing, mastering, MIDI composition, and full music production workflows with 130 tools.1872,642 PyPI104MIT
- AlicenseBqualityDmaintenanceThis 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.40MIT