reaper-mcp
# dawmcp
[](https://github.com/vecnode/dawmcp/actions/workflows/ci.yml)
[](Cargo.toml)
[](LICENSE)
A comprehensive MCP for Digital Audio Workstations (DAWs).
It connects Claude to a live, running DAW instance - controlling transport,
tracks, FX, and rendering - through a DAW-agnostic tool surface, with a
per-DAW adapter behind it.
## Architecture
```
Claude <--stdio--> dawmcp (Rust, rmcp, --daw=reaper|audacity) --> DawBackend trait --> adapter
|
dawmcp-reaper (file IPC --> reaper_bridge.lua --> reaper.* API)
dawmcp-audacity (mod-script-pipe named pipes/FIFOs --> Audacity)
```
`dawmcp-core` defines DAW-agnostic traits (`Transport`, `Tracks`, `Fx`,
`Render`, `Project`, `Status`) so the same MCP tools work over any DAW that
implements them. DAW-specific concepts that don't generalize (REAPER's
`run_reascript` escape hatch, Audacity's lack of a persistent FX chain) live
only in that adapter, not in the shared core. `dawmcp-server` picks which
adapter to serve via `--daw=reaper` (default) or `--daw=audacity`; `.mcp.json`
registers both as separate MCP server entries so Claude can connect to
either (or both) at once.
The REAPER adapter (`crates/dawmcp-reaper`) talks to REAPER the same way the
original Python implementation did: the server writes one JSON request file
per call into a bridge directory, `lua/reaper_bridge.lua` picks it up on its
next `reaper.defer()` tick (REAPER's UI frame rate, ~16-33ms round trip) and
writes a JSON response back - no REAPER extensions required. See
[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for the full design writeup and
why this is file IPC rather than a socket.
The Audacity adapter (`crates/dawmcp-audacity`) talks to Audacity's built-in
`mod-script-pipe` module (named pipes on Windows, FIFOs on Linux/Mac) - every
command it sends is verified against Audacity's own source, not assumed.
Audacity must have mod-script-pipe enabled once yourself (Edit > Preferences
> Modules) - dawmcp won't flip that on for you, since it's a
security-relevant setting Audacity's own docs warn about (any program can
then control Audacity with no notification).
## Status
The Rust workspace has full REAPER tool parity with the original Python
implementation, verified against a real running REAPER instance (the Python
package has been removed; `git log` has its history). The Audacity adapter
covers transport (play/stop/pause/record), track add/remove/rename/list,
per-track volume/pan/mute/solo, and render/export - also verified against a
real Audacity install's process/path discovery on this machine. Not yet
supported for Audacity (by design, not by omission - see
[AGENTS.md](AGENTS.md) for why): seeking/tempo/transport-state queries, FX,
and per-track color.
## Requirements
- [Rust](https://rustup.rs/) (stable toolchain, via `rustup`)
- REAPER (tested on 6.x/7.x) for the REAPER adapter, and/or Audacity (3.x)
for the Audacity adapter - use either or both. REAPER needs no
extensions. Audacity needs `mod-script-pipe` enabled once yourself:
Edit > Preferences > Modules > set `mod-script-pipe` to "Enabled", then
restart Audacity.
## Setup
1. Run [build.bat](build.bat) (double-click it, or `cargo build --release`
yourself), which builds `dawmcp` and installs REAPER's bridge for every
detected REAPER install.
2. Point Claude Code (or Claude Desktop) at it - `.mcp.json` in this repo
already registers both:
```json
{
"mcpServers": {
"reaper": {
"command": "<path-to-this-repo>/target/release/dawmcp"
},
"audacity": {
"command": "<path-to-this-repo>/target/release/dawmcp",
"args": ["--daw=audacity"]
}
}
}
```
For REAPER: on every launch, `dawmcp` auto-detects and installs
`lua/reaper_bridge.lua` (plus the default project and startup hook, see
below) into every REAPER install it finds, idempotently, before serving.
No separate setup script or manual Actions-list step needed. Pass
`--no-install` to skip this and just serve.
3. If REAPER is **already open** when `dawmcp` first installs the startup
hook, it won't retroactively start the bridge this session - either fully
quit and reopen REAPER, or load it once manually: **Actions -> Show
action list -> New action -> Load ReaScript...**, select
`reaper_bridge.lua`, then **Run** it. You should see the small status
window appear (see "Status window" below).
Useful standalone commands (no MCP client needed):
```
dawmcp --status # diagnostics for every detected DAW: installs found? reachable?
dawmcp --install-bridge # install/update the REAPER bridge for every detected REAPER, then exit
dawmcp --daw=audacity # serve Audacity's tools instead of REAPER's
```
If a REAPER tool call errors with "bridge heartbeat not found or stale",
the bridge script isn't currently running in REAPER (REAPER was closed, the
script was stopped, or it crashed) - reload/rerun it via the Actions list.
If an Audacity tool call errors with "could not open Audacity's
mod-script-pipe", either Audacity isn't running or `mod-script-pipe` isn't
enabled (see Requirements above). Call the `daw_status` tool for
diagnostics either way.
## Default project
[reaper_project/default.RPP](reaper_project/default.RPP) is a blank,
track-less project checked into this repo (generated by REAPER itself, not
hand-authored, so its file format is guaranteed valid). `dawmcp` copies it
into REAPER's resource path as `reaper-mcp-default.RPP` and adds a
`reaper.Main_openProject(...)` call to the same `__startup.lua` block that
installs the bridge, so REAPER opens this clean project automatically on
every launch instead of whatever it would otherwise default to.
## Status window
Once the bridge is running, a small status window appears in REAPER,
**docked by default** (not floating). It shows:
- **"Status: ON"** - the bridge has no on/off toggle; once loaded it runs for
as long as REAPER is open, independent of whether this window is open
- Green **"Active"** if a request was processed in the last ~3 seconds, gray
**"Idle"** otherwise, plus a running request count
- A quick reference list of available tool domains
## Tool overview
DAW-agnostic tools (`dawmcp-core`'s `DawBackend` trait), backed by whichever
adapter is active (`--daw=reaper`, the default, or `--daw=audacity`):
| Domain | Tools | Audacity support |
|---|---|---|
| Status | `daw_status` | yes |
| Transport | `transport_play/stop/pause/record/seek/set_tempo/get_state` | play/stop/pause/record only - no verified seek, tempo, or state query |
| Tracks | `track_add/remove/rename/set_volume_db/set_pan/set_mute/set_solo/set_color/list` - `-1` as `track_index` means the master bus on REAPER, everywhere a track-taking tool accepts one | all but `set_color` (Audacity's colour is a small preset enum, not RGB) |
| FX | `fx_add/remove/set_enabled/list/set_param/get_param` | not supported - Audacity has no persistent per-track FX chain like REAPER's |
| Render | `render_project(output_path, start_seconds, end_seconds, overwrite)` | yes, via `Export2` |
| Project | `project_save`, `project_undo` | yes (`Save`/`Undo` - see AGENTS.md for an unverified edge case on never-saved projects) |
REAPER-only tools (no cross-DAW equivalent, exposed via `dawmcp-reaper`'s
inherent methods rather than the shared trait):
| Domain | Tools |
|---|---|
| MIDI | `midi_add_item`, `midi_add_note` |
| Items | `item_split/move/glue_selected/render_in_place_selected` |
| Markers | `marker_add`, `region_add` |
| View | `view_zoom_to_selection`, `view_scroll_to`, `view_set_arrange_zoom` |
| Actions | `action_run(command_id)`, `action_get_toggle_state(command_id)` |
| Compose | `compose_and_render(output_path, notes, track_name)` - one call: new track + MIDI notes + render to audio |
| Escape hatch | `run_reascript(code)` - arbitrary ReaScript Lua |
These REAPER-only tools return a clear error if called against
`--daw=audacity` instead of silently doing nothing.
## Development
```
cargo build
cargo test --workspace
```
## License
Licensed under the [MIT License](LICENSE).
TDQS
Scored across 40 tools
Each tool targets a distinct action on a specific resource (e.g., transport_play vs transport_pause, fx_add vs fx_list). Even the two info tools (reaper_info, reaper_status) serve different diagnostic purposes. No ambiguity or overlap exists.
All tools follow a consistent verb_noun or domain_verb_noun pattern with underscores (e.g., track_add, fx_set_param, transport_stop). The only outlier is install_bridge, but it still follows the verb_noun convention. No mixing of styles.
With 40 tools, this server is well beyond the typical 3-15 range for a well-scoped server. While REAPER is a complex DAW, the granularity could be reduced (e.g., combining transport tools into a single tool with actions). The high count makes it heavy for an MCP server.
Core operations for tracks, FX, transport, and items are covered, but notable gaps exist (e.g., deleting markers/regions, editing MIDI notes beyond adding, managing sends/receives). The run_reascript tool partially mitigates this by allowing arbitrary code, but the dedicated tool surface is incomplete.