# REAPER MCP (pypi · twelvetake-reaper-mcp)

Lets an AI assistant work in your open REAPER project: mixing, MIDI, routing and rendering.

- Trust score: 81/100 (high trust)
- Change this week: +19
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-10-05

## Components

- pypi · `twelvetake-reaper-mcp`: 81/100 (this document), [markdown](https://verifymcp.io/servers/com-twelvetake-reaper-mcp/twelvetake-reaper-mcp.md), [page](https://verifymcp.io/servers/com-twelvetake-reaper-mcp/twelvetake-reaper-mcp)

## Channel facts

- Registry: `pypi`
- Package: `twelvetake-reaper-mcp`
- Version: `1.8.0`
- Transport: `stdio`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-10-05.

- **Supply Chain Security**: 100/100
  - No malware found by supply-chain analysis.
  - No known CVEs affecting this package version or its production dependencies.
  - Runs hatchling.build at install time, a recognised build step with no custom scripting around it.
  - 0 of 28 dependencies flagged as unhealthy.
- **Provenance & Transparency**: 97/100
  - Source repository is publicly reachable at the declared URL.
  - Cryptographically verified build provenance (signed, bound to TwelveTake-Studios/reaper-mcp).
  - Clear OSI-approved license (MIT).
  - Actively maintained (last published 5 days ago).
  - Disclosure check failed: no security disclosure policy was found in the source repository.
- **Schema Quality & AI Usability**: 71/100
  - AI-judged instruction clarity (good).
  - Tool/resource definitions use about 14311 tokens (~79/item across 179 items; 179 tools + 0 resources), lean.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 23/100
  - Stability observed for 7 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 67/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 0% of tool parameters carry a description.
- **Tool Safety**: 99/100
  - No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.
  - 21 of 22 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation; "get_track_master_send" implies "send" and declares readOnlyHint instead, contradicting what its own name says it does.
  - An AI judge read all 180 captured unit(s) of tool text and found none that tries to manipulate the model reading it.
- **Capabilities**: 100/100
  - Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.

## Install

### How do I install the REAPER MCP server?

REAPER MCP runs locally as a PyPI package, launched with uvx twelvetake-reaper-mcp. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

### Claude

```bash
claude mcp add com-twelvetake-reaper-mcp -- uvx twelvetake-reaper-mcp
```

### Cursor

```json
{
  "mcpServers": {
    "com-twelvetake-reaper-mcp": {
      "command": "uvx",
      "args": [
        "twelvetake-reaper-mcp"
      ]
    }
  }
}
```

### VS Code

```json
{
  "servers": {
    "com-twelvetake-reaper-mcp": {
      "command": "uvx",
      "args": [
        "twelvetake-reaper-mcp"
      ]
    }
  }
}
```

### Codex

```bash
codex mcp add com-twelvetake-reaper-mcp -- uvx twelvetake-reaper-mcp
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "com-twelvetake-reaper-mcp": {
      "type": "local",
      "command": [
        "uvx",
        "twelvetake-reaper-mcp"
      ],
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add com-twelvetake-reaper-mcp --command uvx --arg twelvetake-reaper-mcp
```

### Hermes

```yaml
mcp_servers:
  com-twelvetake-reaper-mcp:
    command: "uvx"
    args: ["twelvetake-reaper-mcp"]
```

### Netclaw

```json
{
  "McpServers": {
    "com-twelvetake-reaper-mcp": {
      "Transport": "stdio",
      "Command": "uvx",
      "Arguments": [
        "twelvetake-reaper-mcp"
      ]
    }
  }
}
```

### Vellum

```bash
assistant mcp add com-twelvetake-reaper-mcp -t stdio -c uvx -a twelvetake-reaper-mcp
```

### Other

```json
{
  "mcpServers": {
    "com-twelvetake-reaper-mcp": {
      "command": "uvx",
      "args": [
        "twelvetake-reaper-mcp"
      ]
    }
  }
}
```

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-10-05 (score 81, +1)

No change was recorded against any check on this day. Stability & Change Management went from 20 to 23. That category is still filling its 30-day observation window: 6 days of observed history at the previous scan, 7 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-10-03 (score 80, +1)

No change was recorded against any check on this day. Stability & Change Management went from 13 to 17. That category is still filling its 30-day observation window: 4 days of observed history at the previous scan, 5 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-10-01 (score 79, +1)

No change was recorded against any check on this day. Stability & Change Management went from 7 to 10. That category is still filling its 30-day observation window: 2 days of observed history at the previous scan, 3 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-09-30 (score 78, +15)

- [security improvement] Malware scan: unverified → pass

### 2026-09-29 (score 63, +1)

- [security improvement] Malware scan: unverified → pass
- [functional improvement] Stability: unverified → 0.03
- [functional] Package version: 1.7.7 → 1.8.0
- [functional] Package version: 1.7.7 → 1.7.8

### 2026-09-28 (score 62)

First indexed and scored.

## MCP tools (179)

### `get_track_count` (~26 tokens)

Get the total number of tracks in the current REAPER project (excluding master track).

### `get_track` (~59 tokens)

Get information about a track.

Returns:
    Object with 'info': guid, name, volume, volume_db, pan, muted, soloed,
    has_midi, has_audio, fx_names, role.

Input parameters:

- `track_index` (integer, required)

### `get_all_tracks` (~18 tokens)

Get information about all tracks in the project.

### `get_master_track` (~16 tokens)

Get information about the master track.

### `insert_track` (~71 tokens)

Insert a new track at the specified index.

Args:
    index: Position to insert track (0-based). If not specified, adds at end.
    name: Optional name for the new track.

Returns:
    Info about the created track.

Input parameters:

- `index` (integer)
- `name` (string)

### `delete_track` (~41 tokens)

Delete a track.

Args:
    track_index: Track index to delete (0-based). Cannot delete master track (-1).

Input parameters:

- `track_index` (integer, required)

### `set_track_name` (~42 tokens)

Set the name of a track.

Args:
    name: New name for the track.

Input parameters:

- `name` (string, required)
- `track_index` (integer, required)

### `set_track_volume` (~60 tokens)

Set the volume of a track in decibels.

Args:
    volume_db: Volume in dB (0 = unity gain, -inf to +12 typical range).

Input parameters:

- `track_index` (integer, required)
- `volume_db` (number, required)

### `set_track_pan` (~62 tokens)

Set the pan position of a track.

Args:
    pan: Pan position from -1.0 (full left) to 1.0 (full right). 0 = center.

Input parameters:

- `pan` (number, required)
- `track_index` (integer, required)

### `set_track_mute` (~47 tokens)

Set the mute state of a track.

Args:
    mute: True to mute, False to unmute.

Input parameters:

- `mute` (boolean, required)
- `track_index` (integer, required)

### `set_track_solo` (~47 tokens)

Set the solo state of a track.

Args:
    solo: True to solo, False to unsolo.

Input parameters:

- `solo` (boolean, required)
- `track_index` (integer, required)

### `track_fx_get_count` (~40 tokens)

Get the number of FX plugins on a track.

Returns:
    Object with 'ret' field containing count.

Input parameters:

- `track_index` (integer, required)

### `track_fx_get_list` (~84 tokens)

Get list of all FX plugins on a track.

Returns:
    Object with 'fx' array, one entry per FX with index, name, enabled and offline,
    plus fx_count. 'enabled' is False when the FX is bypassed. Normal FX chain only,
    not input/record FX or master monitoring FX.

Input parameters:

- `track_index` (integer, required)

### `track_fx_add_by_name` (~135 tokens)

Add an FX plugin to a track by name.

Args:
    fx_name: Name of the FX plugin to add (e.g., "ReaEQ", "ReaComp", "ReaLimit").
             Use the exact plugin name as it appears in REAPER's FX browser.
    position: Optional insertion position (0-based) in the FX chain.
              Default -1 adds at the end; 0 inserts at the beginning.

Returns:
    Info about the added FX including its index.

Input parameters:

- `fx_name` (string, required)
- `position` (integer)
- `track_index` (integer, required)

### `track_fx_move` (~85 tokens)

Move an FX plugin to a new position within the same track's FX chain.

Args:
    fx_index: Current FX index (0-based) in the FX chain.
    new_position: Target position (0-based). 0 = beginning of the chain.

Input parameters:

- `fx_index` (integer, required)
- `new_position` (integer, required)
- `track_index` (integer, required)

### `track_fx_delete` (~33 tokens)

Remove an FX plugin from a track.

Input parameters:

- `fx_index` (integer, required)
- `track_index` (integer, required)

### `track_fx_get_name` (~34 tokens)

Get the name of an FX plugin.

Input parameters:

- `fx_index` (integer, required)
- `track_index` (integer, required)

### `track_fx_get_enabled` (~47 tokens)

Get the enabled state of an FX plugin.

Returns:
    Object with 'ret' field (boolean).

Input parameters:

- `fx_index` (integer, required)
- `track_index` (integer, required)

### `track_fx_set_enabled` (~53 tokens)

Enable or disable an FX plugin.

Args:
    enabled: True to enable, False to bypass.

Input parameters:

- `enabled` (boolean, required)
- `fx_index` (integer, required)
- `track_index` (integer, required)

### `track_fx_get_num_params` (~37 tokens)

Get the number of parameters for an FX plugin.

Input parameters:

- `fx_index` (integer, required)
- `track_index` (integer, required)

### `track_fx_get_param_name` (~43 tokens)

Get the name of an FX parameter.

Input parameters:

- `fx_index` (integer, required)
- `param_index` (integer, required)
- `track_index` (integer, required)

### `track_fx_get_param` (~58 tokens)

Get a specific parameter value of an FX plugin.

Returns:
    Object with value, min, max for the parameter.

Input parameters:

- `fx_index` (integer, required)
- `param_index` (integer, required)
- `track_index` (integer, required)

### `track_fx_set_param` (~72 tokens)

Set a parameter value on an FX plugin.

Args:
    value: New value for the parameter (typically normalized 0-1, check min/max).

Input parameters:

- `fx_index` (integer, required)
- `param_index` (integer, required)
- `track_index` (integer, required)
- `value` (number, required)

### `take_fx_get_count` (~58 tokens)

Get the number of FX plugins on a take.

Returns:
    Object with 'ret' field containing the FX count.

Input parameters:

- `item_index` (integer, required)
- `take_index` (integer, required)
- `track_index` (integer, required)

### `take_fx_get_list` (~66 tokens)

Get a list of all FX plugins on a take.

Returns:
    Object with 'fx' array, each entry having index, name, and enabled state.

Input parameters:

- `item_index` (integer, required)
- `take_index` (integer, required)
- `track_index` (integer, required)

### `take_fx_add_by_name` (~122 tokens)

Add an FX plugin to a take by name.

Args:
    fx_name: Name of the FX plugin to add (e.g., "ReaEQ", "ReaComp"). Use the exact
             plugin name as it appears in REAPER's FX browser.

Returns:
    Object with 'ret' field containing the new FX index (or -1 if it could not be added).

Input parameters:

- `fx_name` (string, required)
- `item_index` (integer, required)
- `take_index` (integer, required)
- `track_index` (integer, required)

### `take_fx_delete` (~51 tokens)

Remove an FX plugin from a take.

Args:

Input parameters:

- `fx_index` (integer, required)
- `item_index` (integer, required)
- `take_index` (integer, required)
- `track_index` (integer, required)

### `take_fx_get_name` (~55 tokens)

Get the name of an FX plugin on a take.

Args:

Input parameters:

- `fx_index` (integer, required)
- `item_index` (integer, required)
- `take_index` (integer, required)
- `track_index` (integer, required)

### `take_fx_get_enabled` (~73 tokens)

Get the enabled (not bypassed) state of an FX plugin on a take.

Args:

Returns:
    Object with 'ret' field (boolean).

Input parameters:

- `fx_index` (integer, required)
- `item_index` (integer, required)
- `take_index` (integer, required)
- `track_index` (integer, required)

### `take_fx_set_enabled` (~72 tokens)

Enable or bypass an FX plugin on a take.

Args:
    enabled: True to enable, False to bypass.

Input parameters:

- `enabled` (boolean, required)
- `fx_index` (integer, required)
- `item_index` (integer, required)
- `take_index` (integer, required)
- `track_index` (integer, required)

### `take_fx_get_num_params` (~58 tokens)

Get the number of parameters for an FX plugin on a take.

Args:

Input parameters:

- `fx_index` (integer, required)
- `item_index` (integer, required)
- `take_index` (integer, required)
- `track_index` (integer, required)

### `take_fx_get_param_name` (~66 tokens)

Get the name of a parameter on a take's FX plugin.

Args:

Input parameters:

- `fx_index` (integer, required)
- `item_index` (integer, required)
- `param_index` (integer, required)
- `take_index` (integer, required)
- `track_index` (integer, required)

### `take_fx_get_param` (~82 tokens)

Get a parameter value on a take's FX plugin.

Args:

Returns:
    Object with 'value', 'min', and 'max' for the parameter.

Input parameters:

- `fx_index` (integer, required)
- `item_index` (integer, required)
- `param_index` (integer, required)
- `take_index` (integer, required)
- `track_index` (integer, required)

### `take_fx_set_param` (~92 tokens)

Set a parameter value on a take's FX plugin.

Args:
    value: New value (typically normalized 0-1; check min/max via take_fx_get_param).

Input parameters:

- `fx_index` (integer, required)
- `item_index` (integer, required)
- `param_index` (integer, required)
- `take_index` (integer, required)
- `track_index` (integer, required)
- `value` (number, required)

### `get_takes` (~61 tokens)

List all takes of a media item.

Returns:
    Object with 'takes' array (each entry: index, name, is_active) and 'ret' = take count.

Input parameters:

- `item_index` (integer, required)
- `track_index` (integer, required)

### `get_active_take` (~59 tokens)

Get the index of the active take of a media item.

Returns:
    Object with 'ret' = active take index (-1 if the item has no active take).

Input parameters:

- `item_index` (integer, required)
- `track_index` (integer, required)

### `set_active_take` (~48 tokens)

Set the active take of a media item (which take plays).

Args:

Input parameters:

- `item_index` (integer, required)
- `take_index` (integer, required)
- `track_index` (integer, required)

### `explode_takes` (~44 tokens)

Explode all takes of a media item in place (each take becomes its own overlapping item).

Input parameters:

- `item_index` (integer, required)
- `track_index` (integer, required)

### `crop_to_active_take` (~41 tokens)

Crop a media item to its active take, discarding all other takes.

Input parameters:

- `item_index` (integer, required)
- `track_index` (integer, required)

### `delete_take` (~64 tokens)

Delete a specific take from a media item.

Args:
    take_index: Take index to delete (0-based). The take is activated first, then removed.

Input parameters:

- `item_index` (integer, required)
- `take_index` (integer, required)
- `track_index` (integer, required)

### `select_comp_lane` (~97 tokens)

Make a fixed lane play exclusively on a track (REAPER 7 lane-based comping).

The track must be in fixed-lane mode (right-click track -> Track lanes). Returns a clear
error if it is not, or if the lane index is out of range.

Args:
    lane_index: Fixed lane index to play exclusively (0-based).

Input parameters:

- `lane_index` (integer, required)
- `track_index` (integer, required)

### `create_send` (~65 tokens)

Create a send from one track to another.

Args:
    src_track: Source track index (0-based).
    dest_track: Destination track index (0-based).

Returns:
    Object with send_index.

Input parameters:

- `dest_track` (integer, required)
- `src_track` (integer, required)

### `delete_send` (~57 tokens)

Delete a send from a track.

Args:
    track_index: Source track index (0-based).
    send_index: Send index (0-based) to delete.

Input parameters:

- `send_index` (integer, required)
- `track_index` (integer, required)

### `set_send_volume` (~64 tokens)

Set the volume of a track send.

Args:
    track_index: Source track index (0-based).
    volume_db: Send volume in dB.

Input parameters:

- `send_index` (integer, required)
- `track_index` (integer, required)
- `volume_db` (number, required)

### `get_track_num_sends` (~28 tokens)

Get the number of sends from a track.

Input parameters:

- `track_index` (integer, required)

### `set_send_dest_channels` (~112 tokens)

Set the destination channels for a send (used for sidechain routing).

Args:
    track_index: Source track index (0-based).
    dest_chan: Destination channel pair (0=1-2 main, 2=3-4 sidechain, 4=5-6, etc.).
               For sidechain compression, use 2 to route to channels 3-4.

Input parameters:

- `dest_chan` (integer, required)
- `send_index` (integer, required)
- `track_index` (integer, required)

### `set_send_source_channels` (~86 tokens)

Set the source channels for a send.

Args:
    track_index: Source track index (0-based).
    src_chan: Source channel (-1=none, 0=stereo 1-2, 1024+n=mono from channel n).

Input parameters:

- `send_index` (integer, required)
- `src_chan` (integer, required)
- `track_index` (integer, required)

### `setup_sidechain_send` (~143 tokens)

Create a sidechain send from one track to another track's FX sidechain input.

This creates a send routed to channels 3-4 of the destination track,
which is the standard sidechain input for compressors like ReaComp.

Args:
    src_track: Source/trigger track index (e.g., kick drum).
    dest_track: Destination track index (e.g., bass with compressor).
    volume_db: Send volume in dB (default 0dB = unity).

Returns:
    Object with send_index and routing info.

Input parameters:

- `dest_track` (integer, required)
- `src_track` (integer, required)
- `volume_db` (number)

### `configure_reacomp_sidechain` (~117 tokens)

Configure ReaComp to use sidechain input for detection.

Args:
    track_index: Track index (0-based) where ReaComp is located.
    fx_index: FX index (0-based) of ReaComp in the FX chain.
    use_sidechain: True to use auxiliary input (channels 3-4), False for main input.

Returns:
    Object with configuration status.

Input parameters:

- `fx_index` (integer, required)
- `track_index` (integer, required)
- `use_sidechain` (boolean)

### `setup_sidechain_compression` (~242 tokens)

Complete sidechain compression setup: creates send and configures compressor.

This is the all-in-one function for setting up sidechain compression.
It creates a send from the trigger track to the target track's sidechain input
and configures ReaComp to listen to that sidechain.

Args:
    trigger_track: Track that triggers compression (e.g., kick drum = track 0).
    target_track: Track to be compressed (e.g., bass = track 1).
    compressor_fx_index: Index of ReaComp in target track's FX chain.
    send_volume_db: Sidechain send volume in dB (default 0dB).

Returns:
    Object with complete setup info.

Example:
    For kick-triggered bass compression where:
    - Drums are on track 0
    - Bass is on track 1 with ReaComp at FX index 2
    Call: setup_sidechain_compression(0, 1, 2)

Input parameters:

- `compressor_fx_index` (integer, required)
- `send_volume_db` (number)
- `target_track` (integer, required)
- `trigger_track` (integer, required)

### `play` (~13 tokens)

Start playback in REAPER.

### `stop` (~13 tokens)

Stop playback in REAPER.

### `get_play_state` (~24 tokens)

Get the current playback state.

Returns:
    Object with play state info.

### `get_cursor_position` (~25 tokens)

Get the edit cursor position.

Returns:
    Object with cursor position in seconds.

### `set_cursor_position` (~34 tokens)

Set the edit cursor position.

Args:
    position: Position in seconds from project start.

Input parameters:

- `position` (number, required)

### `save_project` (~15 tokens)

Save the current REAPER project.

### `get_project_path` (~14 tokens)

Get the project path.

### `get_project_name` (~14 tokens)

Get the project name.

### `get_tempo` (~29 tokens)

Get the tempo at project start as `ret`, and every tempo marker as `tempo_markers`.

### `get_time_signature` (~15 tokens)

Get the project time signature.

### `add_mastering_chain` (~78 tokens)

Add a standard mastering chain to the master track.

Adds the following plugins in order:
1\. ReaEQ (corrective EQ)
2\. ReaComp (glue compression)
3\. ReaEQ (tonal shaping)
4\. ReaLimit (brickwall limiter)

Returns:
    Object with list of added FX indices.

### `add_parallel_compression` (~105 tokens)

Set up New York style parallel compression for a track.

Creates a new bus track with heavy compression, fed by a send from the source track.

Args:
    track_index: Source track index (0-based).
    blend_db: Send level in dB for the compressed signal (default -6dB).

Returns:
    Object with bus_track_index, send_index, and compressor_fx_index.

Input parameters:

- `blend_db` (number)
- `track_index` (integer, required)

### `create_bus` (~76 tokens)

Create a submix/stem bus and route specified tracks to it.

Args:
    name: Name for the bus track.
    source_track_indices: List of track indices to route to this bus.

Returns:
    Object with bus_track_index and routing info.

Input parameters:

- `name` (string, required)
- `source_track_indices` (array, required)

### `add_eq` (~32 tokens)

Add ReaEQ to a track.

Returns:
    Object with fx_index.

Input parameters:

- `track_index` (integer, required)

### `add_compressor` (~33 tokens)

Add ReaComp to a track.

Returns:
    Object with fx_index.

Input parameters:

- `track_index` (integer, required)

### `add_limiter` (~38 tokens)

Add ReaLimit (brickwall limiter) to a track.

Returns:
    Object with fx_index.

Input parameters:

- `track_index` (integer, required)

### `create_midi_item` (~71 tokens)

Create an empty MIDI item on a track.

Args:
    position: Start position in seconds.
    length: Length in seconds.

Returns:
    Object with item info including the new item_index.

Input parameters:

- `length` (number, required)
- `position` (number, required)
- `track_index` (integer, required)

### `get_midi_item` (~48 tokens)

Get information about a MIDI item.

Returns:
    Object with item info including position, length, note count.

Input parameters:

- `item_index` (integer, required)
- `track_index` (integer, required)

### `add_midi_note` (~210 tokens)

Add a MIDI note to an item using musical timing (beats).

Args:
    pitch: MIDI note number (0-127, 60 = middle C).
    velocity: Note velocity (1-127).
    start_beat: Start position in beats from the item start (0 = first beat).
    length_beats: Note length in beats (0.25 = sixteenth, 0.5 = eighth, 1.0 = quarter).

Example:
    Four-on-the-floor kick: add_midi_note(0, 0, 36, 110, start_beat=0, length_beats=0.25)
    then start_beat=1, 2, 3.

Input parameters:

- `channel` (integer)
- `item_index` (integer, required)
- `length_beats` (number, required)
- `pitch` (integer, required)
- `start_beat` (number, required)
- `track_index` (integer, required)
- `velocity` (integer, required)

### `add_midi_notes_batch` (~91 tokens)

Add multiple MIDI notes to an item in one call, using musical timing (beats).

Args:
    notes: List of note dicts with keys: pitch, velocity, start_beat, length_beats,
           channel (optional).

Returns:
    Object with count of notes added.

Input parameters:

- `item_index` (integer, required)
- `notes` (array, required)
- `track_index` (integer, required)

### `get_midi_notes` (~48 tokens)

Get all MIDI notes from an item.

Returns:
    Object with list of notes.

Input parameters:

- `fields`
- `item_index` (integer, required)
- `track_index` (integer, required)

### `delete_midi_note` (~42 tokens)

Delete a MIDI note from an item.

Input parameters:

- `item_index` (integer, required)
- `note_index` (integer, required)
- `track_index` (integer, required)

### `clear_midi_item` (~44 tokens)

Delete all MIDI notes from an item.

Returns:
    Object with count of notes deleted.

Input parameters:

- `item_index` (integer, required)
- `track_index` (integer, required)

### `set_midi_note_velocity` (~62 tokens)

Set the velocity of a MIDI note.

Args:
    velocity: New velocity (1-127).

Input parameters:

- `item_index` (integer, required)
- `note_index` (integer, required)
- `track_index` (integer, required)
- `velocity` (integer, required)

### `transpose_midi_notes` (~193 tokens)

Transpose MIDI notes by a number of semitones (12 = an octave).

A note that would land outside pitch 0-127 keeps its original pitch and is counted in
\`skipped` instead.

Args:
    semitones: Signed shift; positive is up, negative is down. 0 = no-op.

Returns:
    {ok, notes_changed, clamped, skipped, out_of_bounds, notes:[...]}, where `notes` is
    the full note list after the transform, re-indexed.

Input parameters:

- `channel` (integer)
- `end_beat`
- `fields`
- `item_index` (integer, required)
- `pitch_high` (integer)
- `pitch_low` (integer)
- `return_notes` (boolean)
- `semitones` (integer, required)
- `start_beat`
- `track_index` (integer, required)

### `nudge_midi_notes` (~188 tokens)

Shift MIDI notes in time by a number of beats (+ = later, - = earlier).

Start and end move together, so note lengths are preserved. A note pushed before the
item start clamps to it and one pushed past the item end is left there; both count in
\`out_of_bounds`, not `clamped`.

Args:
    amount_beats: Signed beat shift (0.25 = a 16th later, -1.0 = a beat earlier). 0 = no-op.

Input parameters:

- `amount_beats` (number, required)
- `channel` (integer)
- `end_beat`
- `fields`
- `item_index` (integer, required)
- `pitch_high` (integer)
- `pitch_low` (integer)
- `return_notes` (boolean)
- `start_beat`
- `track_index` (integer, required)

### `get_selected_midi_notes` (~177 tokens)

Read the MIDI notes currently SELECTED in REAPER's editor for the active take.

The escape hatch for "operate on what I've selected": select notes by hand in REAPER,
call this to see which they are, then translate that into an explicit value filter
(pitch range / beat window / channel) for the transform tools. Read-only, no undo.

Returns:
    {ok, notes:[...], ret} - the selected notes, same shape as get_midi_notes (each note
    carries item-relative start_beat/end_beat). `index` is REAPER's absolute PPQ-sorted
    note index, so a partial selection is non-contiguous. Empty selection -> notes:[].

Input parameters:

- `fields`
- `item_index` (integer, required)
- `track_index` (integer, required)

### `select_midi_notes` (~155 tokens)

Select the MIDI notes matching the filter, as if clicked in REAPER's MIDI editor.

Args:
    selected: False deselects the matching notes instead; with no filter, clears the selection.
    exclusive: When selecting, deselect every note that does not match.

\`notes_changed` counts notes whose selection flipped.

Input parameters:

- `channel` (integer)
- `end_beat`
- `exclusive` (boolean)
- `fields`
- `item_index` (integer, required)
- `pitch_high` (integer)
- `pitch_low` (integer)
- `return_notes` (boolean)
- `selected` (boolean)
- `start_beat`
- `track_index` (integer, required)

### `set_midi_note` (~285 tokens)

Edit one existing MIDI note in place: pitch, start, length and/or channel. Only the
fields you pass change, and at least one is required. (Velocity: set_midi_note_velocity.)

note_index is REAPER's PPQ-sorted index from get_midi_notes / get_selected_midi_notes and
is unstable - re-read after the edit, since the returned list reflects the new order.

Args:
    pitch: New pitch (0-127).
    start_beat: New start in beats from item start; length is preserved. A start before
        the item start clamps there and is counted in out_of_bounds, not clamped.
    length_beats: New length in beats (> 0), resized from the current start.
    channel: New MIDI channel (0-15).

Returns:
    {ok, notes_changed, clamped, skipped, out_of_bounds, notes:[...]}, or {ok:false, error}
    for a bad index, an empty edit, or an out-of-range value (nothing is written).

Input parameters:

- `channel`
- `fields`
- `item_index` (integer, required)
- `length_beats`
- `note_index` (integer, required)
- `pitch`
- `return_notes` (boolean)
- `start_beat`
- `track_index` (integer, required)

### `ramp_midi_note_velocities` (~201 tokens)

Apply a linear velocity ramp (crescendo / decrescendo) across MIDI notes.

Velocities interpolate by onset: the earliest note in the filtered set gets
start_velocity, the latest gets end_velocity, everything between is linear. Notes
sharing an onset (a chord) get the same velocity. Results clamp to 1-127.

Args:
    start_velocity: Velocity at the earliest onset (1-127; out of range clamps, not an error).
    end_velocity: Velocity at the latest onset (1-127).

Input parameters:

- `channel` (integer)
- `end_beat`
- `end_velocity` (integer, required)
- `fields`
- `item_index` (integer, required)
- `pitch_high` (integer)
- `pitch_low` (integer)
- `return_notes` (boolean)
- `start_beat`
- `start_velocity` (integer, required)
- `track_index` (integer, required)

### `scale_midi_note_velocities` (~286 tokens)

Scale MIDI note velocities: multiply, set to a fixed value, or compress toward a pivot.
Results clamp to 1-127.

Args:
    mode: "multiply" (velocity * ratio), "set" (velocity becomes `value`), or "compress"
        (pivot + (velocity - pivot) * ratio).
    ratio: Multiply factor (>= 0, no upper cap), or compress amount (0.0-1.0, where 0
        collapses every note onto the pivot and 1.0 changes nothing).
    value: Target velocity for "set" mode (1-127).
    pivot: What compress pulls toward (1-127), or -1 for the rounded mean of the matched
        notes' velocities (reported as pivot_used).

Returns:
    {ok, notes_changed, clamped, skipped, out_of_bounds, pivot_used, notes:[...]}.

Input parameters:

- `channel`
- `end_beat`
- `fields`
- `item_index` (integer, required)
- `mode` (string)
- `pitch_high`
- `pitch_low`
- `pivot` (integer)
- `ratio` (number)
- `return_notes` (boolean)
- `start_beat`
- `track_index` (integer, required)
- `value` (integer)

### `strum_midi_notes` (~196 tokens)

Strum chords: stagger the onsets of simultaneous notes so each chord rolls out.

Only onsets move; note lengths are preserved.

Args:
    spread_beats: Total first-to-last onset span within each chord (>= 0; 0 = no-op).
    direction: "up" strikes the lowest note of a chord first, "down" the highest.
    chord_window_beats: Onset tolerance for grouping notes into one chord (0 = exact
        same onset).

Input parameters:

- `channel`
- `chord_window_beats` (number)
- `direction` (string)
- `end_beat`
- `fields`
- `item_index` (integer, required)
- `pitch_high`
- `pitch_low`
- `return_notes` (boolean)
- `spread_beats` (number, required)
- `start_beat`
- `track_index` (integer, required)

### `snap_midi_notes_to_scale` (~386 tokens)

Snap off-key MIDI notes onto a scale (fix a wrong note, force a part into a key).

Notes already in the scale are left alone; each off-scale note moves to the nearest
in-scale pitch, and under `nearest` a tie resolves toward the middle of the selection.
A note with no in-scale pitch left inside 0-127 stays put and is counted in `skipped`.

Args:
    root: Root pitch class, 0-11 (0=C, 1=C#, 2=D ... 11=B).
    mode: Scale name: major, minor, harmonic_minor, melodic_minor, dorian, phrygian,
        lydian, mixolydian, locrian, major_pentatonic, minor_pentatonic, blues,
        whole_tone, chromatic (aliases: ionian, aeolian, natural_minor). Or a custom
        list of semitone intervals from the root, each 0-11 (e.g. [0,2,4,7,9]).
    direction: "nearest" (closest scale tone), "up" or "down" (that way only, skipping
        a note rather than falling back to the other direction).

Returns:
    {ok, notes_changed, clamped, skipped, out_of_bounds, notes:[...]}; `notes` is the
    post-transform list, with indices re-synced after the sort.

Input parameters:

- `channel` (integer)
- `direction` (string)
- `end_beat`
- `fields`
- `item_index` (integer, required)
- `mode`
- `pitch_high`
- `pitch_low`
- `return_notes` (boolean)
- `root` (integer, required)
- `start_beat`
- `track_index` (integer, required)

### `quantize_midi_notes` (~340 tokens)

Quantize MIDI note onsets onto the grid (tighten sloppy timing, add swing).

Onsets snap to the PROJECT bar/beat grid, not to an offset from the item's own start,
and note lengths are preserved: start and end move together. Notes that land past the
item end are kept, and one that would land before the item start is placed at it; both
are counted in `out_of_bounds` (`clamped` stays 0 here).

Args:
    grid: Grid spacing in beats: 0.25 = 1/16, 0.5 = 1/8, 1.0 = 1/4. Must be > 0.
    strength: 0.0-1.0. 1.0 snaps exactly onto the grid, 0.5 moves each note halfway
        there, 0.0 is a no-op.
    swing: 0.0-1.0. 0.0 = straight, 1.0 = full triplet feel (off-beats at 66.7%),
        scaling linearly between. Only the off-beat (odd) grid cells are delayed.

Input parameters:

- `channel` (integer)
- `end_beat`
- `fields`
- `grid` (number)
- `item_index` (integer, required)
- `pitch_high` (integer)
- `pitch_low` (integer)
- `return_notes` (boolean)
- `start_beat`
- `strength` (number)
- `swing` (number)
- `track_index` (integer, required)

### `stretch_midi_notes` (~272 tokens)

Stretch or compress MIDI timing (half-time, double-time, or any ratio).

Each targeted note scales as a rigid unit about one fixed pivot: its distance from the
pivot and its own length both multiply by `factor`, so the rhythm is preserved and only
the speed changes. Notes that land past the item end are kept as-is; one pushed before
the item start begins at the item start but keeps its scaled end, so it comes out
shorter. Both are counted in `out_of_bounds` (`clamped` stays 0 here).

Args:
    factor: Time scale ratio, must be > 0. 2.0 = twice as long (half-time), 0.5 = half
        as long (double-time).
    pivot_beat: The fixed point, in beats from the item start; may be negative. None =
        the earliest targeted onset.

Input parameters:

- `channel` (integer)
- `end_beat`
- `factor` (number, required)
- `fields`
- `item_index` (integer, required)
- `pitch_high` (integer)
- `pitch_low` (integer)
- `pivot_beat`
- `return_notes` (boolean)
- `start_beat`
- `track_index` (integer, required)

### `legato_midi_notes` (~369 tokens)

Close the gaps in a MIDI line (legato), or set every note to one length.

Only note ends move; starts are never touched. "connect" extends each note's end to the
next onset and never shortens anything; a gap wider than max_gap_beats is left as a rest
and counted in gaps_preserved, and the last note is left alone. "fixed" instead sets every
targeted note's length to length_beats. Notes whose new end passes the item end are kept
and reported in out_of_bounds.

Args:
    mode: "connect" (extend each end to the next onset) or "fixed" (set every length).
    voice: connect only. "chordal" extends to the next onset of any note, so a chord's
        notes move together; "per_pitch" extends to the next note of the SAME pitch and
        channel, keeping interleaved voices independent.
    max_gap_beats: connect only. Gaps wider than this are left as rests (>= 0).
    length_beats: fixed only. The length every targeted note is set to (> 0).

Returns:
    {ok, notes_changed, clamped, skipped, out_of_bounds, gaps_preserved, notes:[...]}.

Input parameters:

- `channel` (integer)
- `end_beat`
- `fields`
- `item_index` (integer, required)
- `length_beats` (number)
- `max_gap_beats` (number)
- `mode` (string)
- `pitch_high`
- `pitch_low`
- `return_notes` (boolean)
- `start_beat`
- `track_index` (integer, required)
- `voice` (string)

### `humanize_midi_notes` (~344 tokens)

Humanize MIDI: nudge timing and velocity by small random amounts, reproducibly.

Each note gets its own timing and velocity offset drawn from a bell curve. Note lengths
are preserved (start and end move together) and pitches are never touched. The randomness
is seeded, so the same take with the same seed and settings gives identical results every
time. Velocities are clamped to 1-127 and counted in clamped; notes pushed past the item
end are kept and reported in out_of_bounds.

Unlike the other timing tools, a note pushed before the item start is placed at the
item start and counted in out_of_bounds, not clamped; clamped here counts only the
velocity clamp.

Args:
    timing: Timing spread in beats (standard deviation); 0.02 is a subtle human feel,
        0.0 leaves timing alone.
    velocity: Velocity spread (standard deviation, in velocity units); 0.0 leaves
        velocity alone.
    seed: Any integer. The same seed, settings and take give the same result.
    max_sigma: Cap on how far one note may stray, in multiples of the spread.

Input parameters:

- `channel` (integer)
- `end_beat`
- `fields`
- `item_index` (integer, required)
- `max_sigma` (number)
- `pitch_high` (integer)
- `pitch_low` (integer)
- `return_notes` (boolean)
- `seed` (integer)
- `start_beat`
- `timing` (number)
- `track_index` (integer, required)
- `velocity` (number)

### `remove_overlapping_midi_notes` (~365 tokens)

Clean up overlapping MIDI notes (same pitch stacked on itself).

Two notes conflict only if they share a pitch AND a channel AND overlap in time, so a
chord is never a conflict and notes that merely touch are left alone. "trim" shortens the
earlier note to stop where the next begins, losing nothing; "delete" drops one note of
each overlapping pair, keeping the louder (ties go to the longer note).

Either mode can remove notes: notes stacked on the exact same onset collapse to the
loudest, since there is nothing to trim between them, and a trim left shorter than
min_length_beats is removed rather than left as a click.

Args:
    mode: "trim" (shorten the earlier note) or "delete" (drop the quieter note).
    min_length_beats: A trimmed note left shorter than this is removed instead. Default
        1/128 of a beat; 0 disables it.
    pitch_low, pitch_high: Notes outside the filter are invisible: never touched,
        and never counted as an overlap partner.

Returns:
    {ok, mode, notes_changed, clamped, skipped, out_of_bounds, notes_removed, trimmed,
    deduped, deleted, notes:[...]} where notes_removed = deduped + deleted.

Input parameters:

- `channel` (integer)
- `end_beat`
- `fields`
- `item_index` (integer, required)
- `min_length_beats` (number)
- `mode` (string)
- `pitch_high` (integer)
- `pitch_low` (integer)
- `return_notes` (boolean)
- `start_beat`
- `track_index` (integer, required)

### `insert_audio_file` (~78 tokens)

Insert an audio file onto a track.

Args:
    file_path: Full path to the audio file.
    position: Position in seconds.

Returns:
    Object with track_index, item_index of the created item, and position.

Input parameters:

- `file_path` (string, required)
- `position` (number, required)
- `track_index` (integer, required)

### `get_track_items` (~34 tokens)

Get all media items on a track.

Returns:
    Object with list of items.

Input parameters:

- `track_index` (integer, required)

### `get_item_info` (~49 tokens)

Get information about a media item.

Returns:
    Object with item properties (position, length, take info, etc.).

Input parameters:

- `item_index` (integer, required)
- `track_index` (integer, required)

### `set_item_position` (~50 tokens)

Set the position of a media item.

Args:
    position: New position in seconds.

Input parameters:

- `item_index` (integer, required)
- `position` (number, required)
- `track_index` (integer, required)

### `set_item_length` (~50 tokens)

Set the length of a media item.

Args:
    length: New length in seconds.

Input parameters:

- `item_index` (integer, required)
- `length` (number, required)
- `track_index` (integer, required)

### `delete_item` (~29 tokens)

Delete a media item.

Input parameters:

- `item_index` (integer, required)
- `track_index` (integer, required)

### `duplicate_item` (~38 tokens)

Duplicate a media item.

Returns:
    Object with new item info.

Input parameters:

- `item_index` (integer, required)
- `track_index` (integer, required)

### `split_item` (~64 tokens)

Split a media item at a position.

Args:
    position: Split position in seconds (absolute project time).

Returns:
    Object with info about both resulting items.

Input parameters:

- `item_index` (integer, required)
- `position` (number, required)
- `track_index` (integer, required)

### `set_item_mute` (~56 tokens)

Mute or unmute a media item.

Args:
    mute: True to mute, False to unmute.

Input parameters:

- `item_index` (integer, required)
- `mute` (boolean, required)
- `track_index` (integer, required)

### `set_item_volume` (~52 tokens)

Set the volume of a media item.

Args:
    volume_db: Volume in dB.

Input parameters:

- `item_index` (integer, required)
- `track_index` (integer, required)
- `volume_db` (number, required)

### `set_item_fade_in` (~55 tokens)

Set the fade-in length of a media item.

Args:
    length: Fade-in length in seconds.

Input parameters:

- `item_index` (integer, required)
- `length` (number, required)
- `track_index` (integer, required)

### `set_item_fade_out` (~55 tokens)

Set the fade-out length of a media item.

Args:
    length: Fade-out length in seconds.

Input parameters:

- `item_index` (integer, required)
- `length` (number, required)
- `track_index` (integer, required)

### `set_tempo` (~32 tokens)

Set the project tempo.

Args:
    bpm: Tempo in beats per minute.

Input parameters:

- `bpm` (number, required)

### `set_time_signature` (~64 tokens)

Set the project time signature.

Args:
    numerator: Beats per measure (e.g., 4 for 4/4).
    denominator: Beat unit (e.g., 4 for quarter note).

Input parameters:

- `denominator` (integer, required)
- `numerator` (integer, required)

### `create_project` (~54 tokens)

Create a new REAPER project.

Note: REAPER has no API to name a project that has never been saved, so this server
has no way to name one either. The removed `name` parameter never took effect.

### `open_project` (~36 tokens)

Open a REAPER project file.

Args:
    path: Full path to the .rpp file.

Input parameters:

- `path` (string, required)

### `render_project` (~221 tokens)

Render the project's master mix to an audio file (uses REAPER's last render settings
for format details; a .wav extension selects WAV output).

If the target file already exists, this returns an error unless overwrite=True
(which deletes the existing file first). This is explicit because REAPER's own
behavior on existing files (prompt vs auto-increment) is a user preference, and the
overwrite prompt blocks unattended rendering.

Args:
    output_path: Full path for output file (extension determines format).
    start_time: Start time in seconds (None = project start).
    end_time: End time in seconds (None = project end).
    tail_seconds: Extra seconds to render at end for reverb tails.
    overwrite: True to replace an existing file at output_path.

Returns:
    Object with render status and REAPER's computed output target(s).

Input parameters:

- `end_time` (number)
- `output_path` (string, required)
- `overwrite` (boolean)
- `start_time` (number)
- `tail_seconds` (number)

### `measure_loudness` (~211 tokens)

Measure loudness as REAPER's loudness window does: integrated LUFS, short-term and
momentary max, loudness range, sample peak, plus true peak.

Target: the master (default), a track, or one item (its track's output over the item,
other items muted). start_time/end_time limit it to a range. It runs a render dry run, so
it writes no files, puts selections back and adds no undo step. Measuring the master marks
the project as modified, even though nothing in it changes.

Returns:
    integrated_lufs, short_term_max_lufs, momentary_max_lufs, loudness_range_lu,
    sample_peak_dbfs, true_peak_dbtp, samples_over_0dbfs, duration; a note when a
    figure is approximate or unavailable.

Input parameters:

- `end_time` (number)
- `item_index` (integer)
- `start_time` (number)
- `track_index` (integer)

### `measure_spectrum` (~134 tokens)

Measure tonal balance and stereo image: octave-band levels (31.5 Hz to 16 kHz),
spectral centroid, tilt in dB per octave, stereo correlation overall and below 150 Hz,
side-to-mid level and left/right balance.

Same targets and range as measure_loudness. Levels are dBFS with a full-scale sine at 0,
as in REAPER. Needs the TwelveTake MCP Analyzer, which --install-bridge installs.

Input parameters:

- `end_time` (number)
- `item_index` (integer)
- `start_time` (number)
- `track_index` (integer)

### `render_region` (~53 tokens)

NOT IMPLEMENTED. Use render_project with the region's start/end from get_regions.

Args:
    output_path: Full path for output file.

Input parameters:

- `output_path` (string, required)
- `region_index` (integer, required)

### `add_marker` (~69 tokens)

Add a marker at a position.

Args:
    position: Position in seconds.
    name: Marker name.
    color: Marker color (0 = default).

Returns:
    Object with marker index.

Input parameters:

- `color` (integer)
- `name` (string)
- `position` (number, required)

### `add_region` (~82 tokens)

Add a region.

Args:
    start: Start position in seconds.
    end: End position in seconds.
    name: Region name.
    color: Region color (0 = default).

Returns:
    Object with region index.

Input parameters:

- `color` (integer)
- `end` (number, required)
- `name` (string)
- `start` (number, required)

### `get_markers` (~31 tokens)

Get all markers in the project.

Returns:
    Object with list of markers (position, name, index).

### `get_regions` (~32 tokens)

Get all regions in the project.

Returns:
    Object with list of regions (start, end, name, index).

### `delete_marker` (~22 tokens)

Delete a marker by index.

Input parameters:

- `marker_index` (integer, required)

### `delete_region` (~22 tokens)

Delete a region by index.

Input parameters:

- `region_index` (integer, required)

### `go_to_marker` (~25 tokens)

Move the edit cursor to a marker.

Input parameters:

- `marker_index` (integer, required)

### `go_to_region` (~26 tokens)

Move the edit cursor to a region start.

Input parameters:

- `region_index` (integer, required)

### `get_track_envelope` (~62 tokens)

Get a track envelope by name.

Args:
    envelope_name: Envelope name (e.g., "Volume", "Pan", "Mute").

Returns:
    Object with envelope info.

Input parameters:

- `envelope_name` (string, required)
- `track_index` (integer, required)

### `get_envelope_point_count` (~53 tokens)

Get the number of points in an envelope.

Args:
    envelope_name: Envelope name.

Returns:
    Object with point count.

Input parameters:

- `envelope_name` (string, required)
- `track_index` (integer, required)

### `add_envelope_point` (~136 tokens)

Add a point to an envelope.

Args:
    envelope_name: Envelope name.
    time: Time position in seconds.
    value: Envelope value (0.0-1.0 for most envelopes).
    shape: Point shape (0=linear, 1=square, 2=slow start/end, 3=fast start, 4=fast end, 5=bezier).

Returns:
    Object with point index.

Input parameters:

- `envelope_name` (string, required)
- `shape` (integer)
- `time` (number, required)
- `track_index` (integer, required)
- `value` (number, required)

### `get_envelope_points` (~57 tokens)

Get all points from an envelope.

Args:
    envelope_name: Envelope name.

Returns:
    Object with list of points (time, value, shape).

Input parameters:

- `envelope_name` (string, required)
- `track_index` (integer, required)

### `delete_envelope_point` (~48 tokens)

Delete an envelope point.

Args:
    envelope_name: Envelope name.

Input parameters:

- `envelope_name` (string, required)
- `point_index` (integer, required)
- `track_index` (integer, required)

### `clear_envelope` (~41 tokens)

Delete all points from an envelope.

Args:
    envelope_name: Envelope name.

Input parameters:

- `envelope_name` (string, required)
- `track_index` (integer, required)

### `set_track_automation_mode` (~65 tokens)

Set the automation mode for a track.

Args:
    mode: 0=trim/read, 1=read, 2=touch, 3=write, 4=latch.

Input parameters:

- `mode` (integer, required)
- `track_index` (integer, required)

### `arm_track_envelope` (~63 tokens)

Arm or disarm an envelope for recording.

Args:
    envelope_name: Envelope name.
    arm: True to arm, False to disarm.

Input parameters:

- `arm` (boolean)
- `envelope_name` (string, required)
- `track_index` (integer, required)

### `get_fx_envelope` (~114 tokens)

Get or create an automation envelope for an FX parameter.

This enables automation of any FX parameter (e.g., a flanger knob in Guitar Rig).
The envelope is created if it doesn't exist.

Args:
    param_index: Parameter index (0-based). Use track_fx_get_num_params() to find available parameters.

Returns:
    Object with envelope_name, param_name, point_count, and indices.

Input parameters:

- `fx_index` (integer, required)
- `param_index` (integer, required)
- `track_index` (integer, required)

### `add_fx_envelope_point` (~144 tokens)

Add an automation point to an FX parameter envelope.

Args:
    time: Time position in seconds.
    value: Parameter value (typically 0.0-1.0, normalized).
    shape: Point shape (0=linear, 1=square, 2=slow start/end, 3=fast start, 4=fast end, 5=bezier).

Returns:
    Object with point_index and confirmation.

Input parameters:

- `fx_index` (integer, required)
- `param_index` (integer, required)
- `shape` (integer)
- `time` (number, required)
- `track_index` (integer, required)
- `value` (number, required)

### `get_fx_envelope_points` (~64 tokens)

Get all automation points from an FX parameter envelope.

Returns:
    Object with list of points (time, value, shape, tension, selected).

Input parameters:

- `fx_index` (integer, required)
- `param_index` (integer, required)
- `track_index` (integer, required)

### `delete_fx_envelope_point` (~68 tokens)

Delete an automation point from an FX parameter envelope.

Args:
    point_index: Point index (0-based) to delete.

Input parameters:

- `fx_index` (integer, required)
- `param_index` (integer, required)
- `point_index` (integer, required)
- `track_index` (integer, required)

### `clear_fx_envelope` (~52 tokens)

Clear all automation points from an FX parameter envelope.

Returns:
    Object with deleted_count.

Input parameters:

- `fx_index` (integer, required)
- `param_index` (integer, required)
- `track_index` (integer, required)

### `undo` (~23 tokens)

Undo the last action in REAPER.

Returns:
    Object with undo description.

### `redo` (~25 tokens)

Redo the last undone action in REAPER.

Returns:
    Object with redo description.

### `get_undo_state` (~28 tokens)

Get the current undo/redo state.

Returns:
    Object with undo and redo descriptions.

### `select_track` (~41 tokens)

Select a track.

Args:
    exclusive: If True, deselect other tracks first.

Input parameters:

- `exclusive` (boolean)
- `track_index` (integer, required)

### `select_all_tracks` (~13 tokens)

Select all tracks.

### `unselect_all_tracks` (~15 tokens)

Unselect all tracks.

### `get_selected_tracks` (~27 tokens)

Get indices of all selected tracks.

Returns:
    Object with list of selected track indices.

### `select_all_items` (~14 tokens)

Select all media items.

### `unselect_all_items` (~16 tokens)

Unselect all media items.

### `get_selected_items` (~25 tokens)

Get all selected media items.

Returns:
    Object with list of selected items.

### `copy_selected_items` (~15 tokens)

Copy selected items to clipboard.

### `cut_selected_items` (~15 tokens)

Cut selected items to clipboard.

### `paste_items` (~16 tokens)

Paste items from clipboard at edit cursor.

### `delete_selected_items` (~14 tokens)

Delete all selected items.

### `set_time_selection` (~46 tokens)

Set the time selection.

Args:
    start: Start time in seconds.
    end: End time in seconds.

Input parameters:

- `end` (number, required)
- `start` (number, required)

### `get_time_selection` (~25 tokens)

Get the current time selection.

Returns:
    Object with start and end times.

### `clear_time_selection` (~14 tokens)

Clear the time selection.

### `set_track_phase` (~46 tokens)

Set the phase inversion of a track.

Args:
    invert: True to invert phase, False for normal.

Input parameters:

- `invert` (boolean, required)
- `track_index` (integer, required)

### `set_track_width` (~57 tokens)

Set the stereo width of a track.

Args:
    width: Width value (0=mono, 1=stereo, 2=200% width).

Input parameters:

- `track_index` (integer, required)
- `width` (number, required)

### `set_track_as_folder` (~59 tokens)

Set a track as a folder parent or child.

Args:
    folder_depth: 0=normal, 1=folder parent, -1=end of folder.

Input parameters:

- `folder_depth` (integer, required)
- `track_index` (integer, required)

### `arm_track` (~46 tokens)

Arm or disarm a track for recording.

Args:
    arm: True to arm, False to disarm.

Input parameters:

- `arm` (boolean)
- `track_index` (integer, required)

### `set_track_input` (~59 tokens)

Set the record input for a track.

Args:
    input_index: Input index (-1=no input, 0+=hardware inputs, 4096+=virtual MIDI).

Input parameters:

- `input_index` (integer, required)
- `track_index` (integer, required)

### `set_track_monitor` (~54 tokens)

Set the monitor mode for a track.

Args:
    monitor: 0=off, 1=normal, 2=not when playing.

Input parameters:

- `monitor` (integer, required)
- `track_index` (integer, required)

### `set_track_color` (~77 tokens)

Set the color of a track.

Args:
    r: Red component (0-255).
    g: Green component (0-255).
    b: Blue component (0-255).

Input parameters:

- `b` (integer, required)
- `g` (integer, required)
- `r` (integer, required)
- `track_index` (integer, required)

### `get_track_peak` (~60 tokens)

Get the current peak level of a track.

Args:
    channel: Channel (0=left, 1=right).

Returns:
    Object with peak value in dB.

Input parameters:

- `channel` (integer)
- `track_index` (integer, required)

### `get_track_peak_hold` (~99 tokens)

Get the peak hold level of a track (highest peak since meters were last reset).

Returns the max peak from a previous playback without needing to be actively
playing - play the project, stop, then call this for gain staging.

Args:
    channel: Channel (0=left, 1=right).

Returns:
    Object with peak hold value in dB.

Input parameters:

- `channel` (integer)
- `track_index` (integer, required)

### `clear_all_peak_indicators` (~50 tokens)

Clear the peak hold indicators on all tracks (including master).

Resets the held peak values that accumulate during playback. Use before a
fresh playback pass when you want clean readings for gain staging.

### `get_track_master_send` (~48 tokens)

Get the master/parent send state of a track.

Returns:
    Object with 'ret' field (1 = enabled, 0 = disabled).

Input parameters:

- `track_index` (integer, required)

### `set_track_master_send` (~96 tokens)

Enable or disable the master/parent send on a track.

When enabled, the track's audio routes to its parent folder track (or the
master if it has no parent). Disable it when a track should only output
through its sends (e.g., routed exclusively to a bus).

Args:
    enabled: True to enable, False to disable.

Input parameters:

- `enabled` (boolean, required)
- `track_index` (integer, required)

### `run_action` (~39 tokens)

Run a REAPER action by command ID.

Args:
    action_id: REAPER action/command ID number.

Input parameters:

- `action_id` (integer, required)

### `run_action_by_name` (~155 tokens)

Run a REAPER action by its named command id.

Named commands (e.g. ReaScripts "_RS12345" or SWS "_SWS_...") are resolved
to a numeric command id via NamedCommandLookup before firing. A purely numeric
string (e.g. "40297") is treated as a built-in command id and run directly;
prefer run_action(action_id) for built-ins.

Args:
    action_name: Named command id (e.g. "_RS12345") or a numeric command id string.

Returns:
    If the named command cannot be resolved,
    returns {"ok": False, "error": ...} without firing any action.

Input parameters:

- `action_name` (string, required)

### `get_fx_presets` (~45 tokens)

Get list of presets available for an FX.

Returns:
    Object with list of preset names.

Input parameters:

- `fx_index` (integer, required)
- `track_index` (integer, required)

### `get_fx_preset` (~44 tokens)

Get the current preset name of an FX.

Returns:
    Object with current preset name.

Input parameters:

- `fx_index` (integer, required)
- `track_index` (integer, required)

### `set_fx_preset` (~51 tokens)

Set the preset of an FX.

Args:
    preset_name: Preset name.

Input parameters:

- `fx_index` (integer, required)
- `preset_name` (string, required)
- `track_index` (integer, required)

### `save_fx_preset` (~55 tokens)

Save the current FX settings as a preset.

Args:
    preset_name: Name for the new preset.

Input parameters:

- `fx_index` (integer, required)
- `preset_name` (string, required)
- `track_index` (integer, required)

### `get_eq_bands` (~118 tokens)

Get all ReaEQ band settings in one structured call.

Args:
    fx_index: FX index (0-based) of ReaEQ in the FX chain.

Returns:
    Object with a 'bands' list. Each band has band_index, bandtype,
    bandtype_name, bandidx, paramtype, paramtype_name, normval, the
    REAPER-formatted value, and (for gain params) the computed gain_db.

Input parameters:

- `fx_index` (integer, required)
- `track_index` (integer, required)

### `set_eq_band` (~290 tokens)

Set a ReaEQ band parameter.

Pass real values by default: frequency in Hz (paramtype 0), gain in dB
(paramtype 1), or Q (paramtype 2). Gain is converted to ReaEQ's normalized
curve internally; freq and Q are sent raw.

Args:
    fx_index: FX index (0-based) of ReaEQ.
    bandtype: -1=master gain, 0=hipass, 1=loshelf, 2=band, 3=notch,
              4=hishelf, 5=lopass, 6=bandpass, 7=parallel bandpass.
    bandidx: Band index within that type (0=first). Ignored for master gain.
    paramtype: 0=frequency (Hz), 1=gain (dB), 2=Q. Ignored for master gain.
    value: The value, in real units unless is_normalized=True.
    is_normalized: If True, value is a raw 0-1 normalized value written directly.

Input parameters:

- `bandidx` (integer, required)
- `bandtype` (integer, required)
- `fx_index` (integer, required)
- `is_normalized` (boolean)
- `paramtype` (integer, required)
- `track_index` (integer, required)
- `value` (number, required)

### `get_eq_band_enabled` (~140 tokens)

Check whether a ReaEQ band is enabled.

Args:
    fx_index: FX index (0-based) of ReaEQ.
    bandtype: Band type (0=hipass, 1=loshelf, 2=band, 3=notch, 4=hishelf, 5=lopass).
    bandidx: Band index within that type (0=first).

Returns:
    Object with 'ret' boolean (true=enabled).

Input parameters:

- `bandidx` (integer)
- `bandtype` (integer, required)
- `fx_index` (integer, required)
- `track_index` (integer, required)

### `set_eq_band_enabled` (~143 tokens)

Enable or disable a ReaEQ band.

Args:
    fx_index: FX index (0-based) of ReaEQ.
    bandtype: Band type (0=hipass, 1=loshelf, 2=band, 3=notch, 4=hishelf, 5=lopass).
    bandidx: Band index within that type (0=first).
    enabled: True to enable, False to disable.

Input parameters:

- `bandidx` (integer)
- `bandtype` (integer, required)
- `enabled` (boolean)
- `fx_index` (integer, required)
- `track_index` (integer, required)

### `find_eq` (~79 tokens)

Find ReaEQ on a track, optionally adding it if absent.

Args:
    instantiate: If True and ReaEQ is not present, add it.

Returns:
    Object with 'ret' = the FX index of ReaEQ, or -1 if not found.

Input parameters:

- `instantiate` (boolean)
- `track_index` (integer, required)

### `get_track_fx_chunk` (~84 tokens)

Get the raw state chunk from an FX plugin (includes preset/state data).

Useful for reading VSTi state data like Toontrack EZkeys chord progressions.
The chunk contains the full serialized state of the plugin.

Returns:
    Object with 'chunk' containing the FX state data string.

Input parameters:

- `fx_index` (integer, required)
- `track_index` (integer, required)

### `get_project_length` (~31 tokens)

Get the length of the project (end of last item).

Returns:
    Object with project length in seconds.

### `get_project_summary` (~244 tokens)

Get a comprehensive summary of the current REAPER project.

Returns everything needed to understand the project state and give
useful mixing/production advice in a single call.

Returns:
    Object with:
    - project_name: Name of the project file
    - project_path: Full path to the project
    - tempo: Project tempo in BPM
    - time_signature: {numerator, denominator}
    - project_length: Length in seconds
    - track_count: Total number of tracks
    - tracks: List of track info objects, each containing:
        - index: Track index (0-based)
        - name: Track name
        - volume_db: Volume in decibels
        - pan: Pan position (-1 to 1)
        - mute: Boolean mute state
        - solo: Boolean solo state
        - fx_count: Number of FX plugins
        - fx_names: List of FX plugin names
    - master: Master track info {volume_db, fx_count, fx_names}
    - markers: List of {index, position, name}
    - regions: List of {index, start, end, name}

### `get_play_position` (~25 tokens)

Get the current playback position.

Returns:
    Object with play position in seconds.

### `record` (~13 tokens)

Start recording in REAPER.

### `pause` (~13 tokens)

Pause playback in REAPER.

### `toggle_repeat` (~23 tokens)

Toggle repeat/loop mode.

Returns:
    Object with new repeat state.

### `get_repeat_state` (~27 tokens)

Get the current repeat state.

Returns:
    Object with repeat state (true/false).

### `zoom_to_selection` (~18 tokens)

Zoom the arrange view to the time selection.

### `zoom_to_project` (~19 tokens)

Zoom the arrange view to show the entire project.

## Diagnostics

Captured diagnostic sections: Provenance, Install scripts, Dependencies. The full working is on the page: https://verifymcp.io/servers/com-twelvetake-reaper-mcp/twelvetake-reaper-mcp#diagnostics

## Score history

- 2026-10-05: 81
- 2026-10-04: 80
- 2026-10-03: 80
- 2026-10-02: 79
- 2026-10-01: 79
- 2026-09-30: 78
- 2026-09-29: 63
- 2026-09-28: 62

## Common questions

### What is the REAPER MCP server?

REAPER MCP is listed in the public MCP registry as com.twelvetake/reaper-mcp. Lets an AI assistant work in your open REAPER project: mixing, MIDI, routing and rendering. This page covers its PyPI package (twelvetake-reaper-mcp).

### Is the REAPER MCP server safe to use?

REAPER MCP scores 81 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 5 October 2026. Its build provenance is signed and verified. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

### What tools does the REAPER MCP server expose?

REAPER MCP exposes 179 tools: get_track_count, get_track, get_all_tracks, get_master_track, insert_track, and 174 more. Their descriptions and schemas cost roughly 13,734 tokens of context every time the server is loaded.

### Is the REAPER MCP server still maintained?

REAPER MCP is still listed as active in the MCP registry. We last reached this channel on 5 October 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

### What licence is the REAPER MCP server under?

REAPER MCP declares the MIT licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.

## Links

- PyPI project: https://pypi.org/project/twelvetake-reaper-mcp/
- Socket report: https://socket.dev/pypi/package/twelvetake-reaper-mcp
- Repository: https://github.com/TwelveTake-Studios/reaper-mcp
- Website: https://twelvetake.com/tools/reaper-mcp/
- Changelog RSS feed: https://verifymcp.io/servers/com-twelvetake-reaper-mcp/twelvetake-reaper-mcp.xml
- Changelog JSON feed: https://verifymcp.io/servers/com-twelvetake-reaper-mcp/twelvetake-reaper-mcp.json
- HTML version of this page: https://verifymcp.io/servers/com-twelvetake-reaper-mcp/twelvetake-reaper-mcp
