Guarded MCP control of REAPER through a local Lua bridge.
Project description
REAPER MCP
A safe, producer-focused MCP server for controlling REAPER with AI, scripts, and the command line.
Quick start · Interfaces · Contributing
What it is
REAPER MCP connects an AI client or local script to a real REAPER project. It keeps the producer in control with typed requests, stable project identities, preflight validation, one-step undo, default-deny file policies, and truthful structured results.
The server runs locally. Python owns the MCP tools, services, safety checks, profiles, and workflows. A Lua bridge runs inside REAPER and executes the approved ReaScript commands.
What producers can do
| Producer workflow | Representative tools | What it enables |
|---|---|---|
| Build | create_song_starter, create_track, create_midi_pattern |
Start a song with tracks, MIDI parts, and a region |
| Arrange | move_media_item, split_media_item, list_fixed_lanes, select_fixed_lane |
Shape sections and safely audition one complete REAPER fixed lane |
| Edit MIDI | add_midi_notes, quantize_midi_notes, humanize_midi_notes, snap_midi_notes_to_scale |
Write, correct, and vary musical performances |
| Mix | set_track_volume, add_fx, setup_sidechain, configure_reference_track |
Balance tracks, build guarded processing chains, and audition references outside master FX |
| Tune vocals | list_vocal_tuning_providers, preview_vocal_tuning_plugin_plan, apply_vocal_tuning_plugin_plan |
Apply approved scale-aware pitch correction through a verified, undoable provider |
| Manage projects | save_project, apply_track_template, freeze_track, undo |
Save, template, freeze, and recover project changes |
| Analyze | measure_audio_file, analyze_audio_program |
Measure loudness, peaks, DC offset, frequency-band balance, and silence |
| Master | create_mastering_session, preview_mastering_plan, prepare_mastering_audition |
Guard master-FX plans, render measured candidates, and prepare level-matched A/B projects |
| Deliver | deliver_mastering_candidate, create_mastering_codec_preview, create_mastering_version_set, prepare_mastering_album |
Verify PCM WAVs, measure decoded AAC/MP3/Opus previews, group approved versions, and prepare albums |
| Render | render_project, render_project_start, render_project_result |
Produce approved WAV output with completion checks |
The default minimal profile exposes 26 focused tools. Opt into production
for 148 stable tools or full for all 172 tools, including experimental vocal
tuning, mastering, and render lifecycle operations.
Interfaces
All interfaces use the same services, profiles, safety rules, error model, and Lua bridge. They are different ways to reach the same product.
| Interface | Best for | Start |
|---|---|---|
| MCP | Claude, Codex, Cursor, and other AI clients | reaper-mcp |
| CLI | Producers, shell scripts, automation, and CI | reaper-mcp-cli |
| REST | Local apps, integrations, and future video or web clients | REAPER_MCP_TRANSPORT=http reaper-mcp |
Quick demo
With REAPER open and the Lua bridge running, a producer can create and inspect a song starter through the same tools an AI client uses. The example below shows the interaction shape; returned GUIDs are then used for later guarded edits.
Producer: Create an 8-bar A-minor song starter and show me what was created.
1. create_song_starter
{"name":"A-minor demo","bars":8,"root_note":69,"mode":"minor"}
-> Creates Drums, Bass, Chords, and Lead parts plus one song region.
The response returns stable track, item, take, and region identities.
2. get_project_snapshot
{}
-> Returns the current project, transport state, tracks, markers, and regions.
3. list_available_fx
{}
-> Returns the FX installed in this REAPER profile.
4. list_track_fx
{"track_guid":"<drums-track-guid>"}
-> Reads the drum track FX chain without changing the project.
Every write is validated before execution and appears as one named REAPER undo step. Read the returned identities instead of guessing from track positions.
Quick start
You can connect REAPER MCP in a few minutes. You need REAPER and
uv. Linux with
REAPER 7.66 is the live-verified environment.
1. Install the server and bridge
Install the Python package as an isolated command-line tool, then copy its packaged Lua bridge into your REAPER resource directory:
uv tool install danishaft-reaper-mcp
reaper-mcp-install
The installer prints the exact bridge path and the remaining REAPER steps. It backs up an older bridge when the installed content differs.
2. Activate the bridge in REAPER
Open REAPER and complete these steps once:
- Choose Actions > Show action list.
- Choose New action > Load ReaScript.
- Select the
reaper_mcp_bridge.luapath printed by the installer. - Select
reaper_mcp_bridge.luain the action list, then choose Run.
Run the bridge again after restarting REAPER. You can add it to a REAPER startup action after confirming the first connection.
3. Start and verify the server
Keep REAPER open with the bridge running. Verify the connection before changing a project:
reaper-mcp-cli health
Then start the MCP server:
reaper-mcp
A successful result reports both the Python server and the REAPER bridge as available. Continue to MCP setup to connect your AI client.
Platform support
The Python package and installer contain platform path handling. GitHub CI runs the unit, contract, lint, format, and package checks on all three platforms, but live DAW acceptance is narrower than source compatibility. Do not treat an unverified platform as production-ready until REAPER has been exercised there.
| Platform | REAPER integration | Status |
|---|---|---|
| Linux | CI plus REAPER 7.66, native Lua bridge, isolated render path | Live verified |
| macOS | CI and installer path handling; live REAPER run pending | CI tested, DAW unverified |
| Windows | CI and installer path handling; live REAPER run pending | CI tested, DAW unverified |
Available tool surface
The server registers 172 tools and exposes 26 focused tools in the default
minimal profile. Use discovery instead of memorizing the complete list.
reaper-mcp-cli tools --pretty
reaper-mcp-cli capabilities --pretty
The production, midi, and mixing profiles provide larger task-specific
surfaces. mixing includes experimental vocal tuning; full also exposes
experimental mastering and render lifecycle operations. The tuning workflow
executes supplied note-segment corrections through stable REAPER take-pitch
controls. It can insert x42 Auto Tune first and directly set its documented
root-scale note mask, correction, smoothing, bias, tuning, fast mode, and wet
controls, or recall an engineer-authored ReaTune preset without editing hidden
plugin state. It does not detect the song key or claim formant-safe correction.
Mastering has local unit, FFmpeg, isolated-child REAPER, Linux
stock master-FX coverage, and one complete Codex-to-MCP isolated mastering
acceptance run. The official EBU v5.0 compliance run passes the selected Tech
3341 loudness and true-peak cases. Retained engineer listening evidence,
deterministic scoring of captured client traces, and macOS/Windows REAPER
acceptance remain pending.
MCP setup
Add the server to an MCP client that supports stdio transport:
{
"mcpServers": {
"reaper-mcp": {
"command": "uvx",
"args": [
"--from",
"danishaft-reaper-mcp",
"reaper-mcp"
],
"env": {
"REAPER_MCP_BRIDGE_DIR": "/tmp/reaper-mcp-bridge"
}
}
}
}
To work on the implementation instead of the released package, clone the repository and point the client at the checkout:
git clone https://github.com/danishaft/reaper-mcp.git
cd reaper-mcp
uv sync --locked
uv run reaper-mcp-install
uv run reaper-mcp
The server exposes the minimal profile by default. Use the profile tools or
set REAPER_MCP_TOOL_PROFILE to choose production, midi, mixing, or
full.
CLI usage
The CLI covers every visible MCP tool through call. The aliases are shortcuts
for common producer operations; they do not create a second implementation.
# Discover the active tool surface.
reaper-mcp-cli tools --pretty
# Call any tool with a JSON object.
reaper-mcp-cli call set_tempo --json '{"bpm": 96}'
# Use readable producer-facing aliases.
reaper-mcp-cli project snapshot
reaper-mcp-cli tracks list
reaper-mcp-cli transport play
reaper-mcp-cli transport stop
# Use the complete profile when an experimental tool is required.
reaper-mcp-cli --profile full tools --pretty
Use --arg key=value for simple scalar arguments and --json for nested
requests. Output is compact JSON by default and supports --pretty.
REST usage
The REST adapter is optional and loopback-only because it has no authentication layer. It reuses the MCP registry and returns the same structured tool results.
export REAPER_MCP_TRANSPORT=http
export REAPER_MCP_HTTP_HOST=127.0.0.1
export REAPER_MCP_HTTP_PORT=8765
reaper-mcp
Available endpoints:
GET /api/health
GET /api/tools
POST /api/tools/{tool_name}
Example:
curl http://127.0.0.1:8765/api/tools/get_active_profile
curl -X POST http://127.0.0.1:8765/api/tools/get_project_snapshot \
-H 'content-type: application/json' \
-d '{}'
Safety model
The bridge and services enforce the following rules before REAPER executes a mutation:
- Stable REAPER GUIDs identify tracks, items, takes, FX, envelopes, and sends.
- Reference tracks can bypass master FX through a verified direct hardware send created in one undoable routing operation.
- Mutations are validated and wrapped in named REAPER undo actions.
- Stale target fingerprints return structured conflicts instead of guessing.
- Audio, project, template, analysis, and render paths use explicit allowlists.
- Template deletion requires the SHA-256 returned by a fresh template listing.
- Render success requires a stable, non-empty output and verified restoration.
- Hidden profile tools cannot be called through stale client discovery.
- A timed-out mutation reports an uncertain outcome and must be refreshed before retrying.
- Bridge failures report structured errors instead of claiming success.
Configuration
Runtime settings use the REAPER_MCP_ prefix. The important paths are:
| Variable | Purpose |
|---|---|
REAPER_MCP_BRIDGE_DIR |
Shared Python and Lua bridge directory |
REAPER_MCP_TOOL_PROFILE |
Active tool profile |
REAPER_MCP_TRANSPORT |
stdio or http |
REAPER_MCP_ALLOWED_MEDIA_SOURCE_ROOTS |
Audio files that may be inserted |
REAPER_MCP_ALLOWED_PROJECT_ROOTS |
Projects that may be saved as |
REAPER_MCP_ALLOWED_RENDER_ROOTS |
Directories allowed for WAV output |
REAPER_MCP_ALLOWED_TEMPLATE_ROOTS |
Directories allowed for templates |
REAPER_MCP_ALLOWED_AUDIO_ROOTS |
Audio files allowed for analysis |
REAPER_MCP_REAPER_EXECUTABLE |
REAPER binary used by isolated rendering |
REAPER_MCP_FFMPEG_EXECUTABLE |
FFmpeg binary used for EBU R128 measurement |
REAPER_MCP_AUDIO_MEASUREMENT_TIMEOUT_SECONDS |
Per-file meter timeout |
REAPER_MCP_AUDIO_MEASUREMENT_MAX_OUTPUT_BYTES |
Meter diagnostic output cap |
All allowlists default to empty. See the full configuration and engineering standards for the complete configuration contract.
Architecture
REAPER MCP has one Python control plane and one execution boundary inside REAPER. MCP, CLI, and REST calls converge on the same tool registry, services, validation, safety rules, and bridge client. An interface never gets a separate implementation of a DAW operation.
Open the image for the full-resolution architecture map. The overview also has a version-controlled Mermaid source and a native editable Excalidraw board.
What happens on a tool call
- The client calls a visible tool through MCP, the CLI, or loopback REST.
- The profile and capability gate decide whether that tool is exposed.
- The tool and service validate the request and enforce path and mutation policies before bridge execution.
- The bridge client writes an atomic JSON envelope with a request ID, mutation classification, dry-run flag, and undo label.
- The Lua bridge polls the request, validates it again at the REAPER boundary, resolves GUIDs against current project state, executes the ReaScript operation, and writes a structured response. Mutating commands run inside one REAPER undo block.
- Python verifies the response request ID, normalizes the response or stable error, then returns it unchanged in meaning through the selected interface.
Synchronous commands use requests/ and responses/. Long-running render
operations use jobs/, so the client can start a job, inspect its status, and
read a completed result without confusing a timeout with a successful render.
Responsibility boundaries
| Layer | Owns | Does not own |
|---|---|---|
| Adapters | MCP, CLI, and HTTP protocol formatting | DAW behavior or safety decisions |
| Tools | Public names, schemas, and thin dispatch | Direct filesystem or REAPER calls |
| Services | Producer workflows, validation, and result shaping | Lua or ReaScript details |
| Bridge client | Request files, polling, timeouts, and cleanup | Musical decisions or project mutation |
| Lua bridge | REAPER execution, GUID resolution, undo blocks, and responses | Client-specific protocol behavior |
This split makes the important guarantees visible: all interfaces share one behavior path, invalid or disallowed work is rejected before bridge execution, and every response identifies what actually happened.
Git history preserves the delivery sequence. Executable unit and opt-in integration tests provide the verification record.
Verification and limitations
The current acceptance evidence covers the bridge, project and track operations, transport, media, MIDI, FX, routing, automation, takes, arrangement, tempo, templates, analysis, workflows, interfaces, and isolated project rendering on Linux with REAPER 7.66. A July 28 targeted run also covers stock ReaEQ, ReaComp, and ReaLimit on the master bus plus guarded mastering plan preview, apply, and undo. An August 4 isolated run covers guarded REAPER 7 whole-lane selection, stale-layout rejection, postcondition checks, and undo.
Run the local checks without REAPER:
uv run pytest
uv run ruff check .
uv run ruff format --check .
Live acceptance is opt-in and requires an isolated REAPER instance with both the bridge and acceptance-probe Lua scripts running:
mkdir -p .private
REAPER_MCP_LIVE_TEST=1 \
REAPER_MCP_BRIDGE_DIR=/tmp/reaper-mcp-bridge \
uv run pytest tests/integration \
--junitxml=.private/live-reaper-acceptance.xml
The ignored JUnit XML file is a machine-readable local record of the live run.
Known limitations are deliberate and documented:
- macOS and Windows have no live REAPER acceptance evidence yet.
- The native render lifecycle remains experimental because action
42230can block the Lua event loop. The isolated external render path is verified. set_fx_presetremains unverified when the installed test FX exposes no preset.- Vocal tuning does not detect the song key. x42 Auto Tune has a verified parameter contract on Linux but no formant correction; ReaTune requires an engineer-authored named preset. The take-pitch bridge command still needs live REAPER acceptance.
- Fixed-lane tools inspect and select complete lanes. Swipe-comp area creation and automatic phrase comping remain out of scope because REAPER does not expose comp areas as stable, directly addressable API objects.
- The Lua bridge must be running inside REAPER before a tool can execute.
- Plugin UI automation, audio-rate control, and cloud collaboration are out of scope.
The opt-in suite under tests/integration/ is the
executable source for live REAPER acceptance.
Demo projects
The demo directory contains lightweight REAPER project fixtures and source notices. Downloaded audio and generated peak files stay local because they are large or subject to separate distribution terms.
Project layout
The repository separates public interfaces, producer logic, typed contracts, REAPER execution, tests, and release documentation.
.
|-- src/reaper_mcp/
| |-- server.py MCP composition root
| |-- cli.py CLI adapter
| |-- rest.py loopback REST adapter
| |-- profiles.py profiles and capability gates
| |-- tools/ thin public tool handlers
| |-- services/ producer workflows and business logic
| |-- models/ typed request and result schemas
| `-- bridge/ Python bridge transport
|-- lua/
| |-- reaper_mcp_bridge.lua REAPER-side dispatcher and runtime
| `-- reaper_mcp_bridge_modules/
| |-- automation_navigation.lua
| |-- command_execution.lua
| |-- fx_arrangement_tempo.lua
| |-- media_midi.lua
| |-- project_routing_transport.lua
| |-- render.lua
| `-- vocal_tuning.lua
|-- tests/
| |-- unit/ tests without REAPER
| `-- integration/ opt-in live REAPER acceptance
|-- docs/ engineering standards and architecture sources
|-- demo/ local producer workflow fixtures
|-- assets/ README and product media
|-- .github/workflows/
| |-- ci.yml Linux, macOS, and Windows CI
| `-- release.yml tagged source and wheel releases
|-- pyproject.toml package metadata and tool configuration
|-- uv.lock reproducible dependency lockfile
`-- README.md product overview and usage guide
Releases and contribution
Tagged releases publish danishaft-reaper-mcp to PyPI through Trusted
Publishing, then attach the same source distribution and wheel to the
GitHub release.
The package still requires a local REAPER installation and a compatible Lua
bridge; it is not a bundled REAPER application.
Read CONTRIBUTING.md for development checks and live acceptance requirements. User-visible changes are tracked in CHANGELOG.md.
License
REAPER MCP is available under the MIT License. See LICENSE and THIRD_PARTY_NOTICES.md for attribution details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file danishaft_reaper_mcp-0.1.0.tar.gz.
File metadata
- Download URL: danishaft_reaper_mcp-0.1.0.tar.gz
- Upload date:
- Size: 2.4 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8944686941726319bbdfce97843c42af85e8840bba94e18a6a67f03534658d07
|
|
| MD5 |
b8c73d52694d429818a5e541580e727e
|
|
| BLAKE2b-256 |
7e51d6170f3d88945a84b66314bbb67fd44ffc43ec642658bb7a2bbcd7b9bf8e
|
Provenance
The following attestation bundles were made for danishaft_reaper_mcp-0.1.0.tar.gz:
Publisher:
release.yml on danishaft/reaper-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
danishaft_reaper_mcp-0.1.0.tar.gz -
Subject digest:
8944686941726319bbdfce97843c42af85e8840bba94e18a6a67f03534658d07 - Sigstore transparency entry: 2340989196
- Sigstore integration time:
-
Permalink:
danishaft/reaper-mcp@1a2e09695643639306f799e990995d455f61da3c -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/danishaft
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@1a2e09695643639306f799e990995d455f61da3c -
Trigger Event:
push
-
Statement type:
File details
Details for the file danishaft_reaper_mcp-0.1.0-py3-none-any.whl.
File metadata
- Download URL: danishaft_reaper_mcp-0.1.0-py3-none-any.whl
- Upload date:
- Size: 256.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0d6c74d8c569714c356ef2ac0dee304f44334d2997ff1353def6e7cce9e21801
|
|
| MD5 |
28357acf88526093a94447bc0f635210
|
|
| BLAKE2b-256 |
8803db1e6f5809224b85787b4c3ec642ffc35c7b68a114fd30db8522d25750a1
|
Provenance
The following attestation bundles were made for danishaft_reaper_mcp-0.1.0-py3-none-any.whl:
Publisher:
release.yml on danishaft/reaper-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
danishaft_reaper_mcp-0.1.0-py3-none-any.whl -
Subject digest:
0d6c74d8c569714c356ef2ac0dee304f44334d2997ff1353def6e7cce9e21801 - Sigstore transparency entry: 2340989208
- Sigstore integration time:
-
Permalink:
danishaft/reaper-mcp@1a2e09695643639306f799e990995d455f61da3c -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/danishaft
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@1a2e09695643639306f799e990995d455f61da3c -
Trigger Event:
push
-
Statement type: