Audacity MCP Server
by PiMPStudios
README.md
# Audacity MCP Server
MCP (Model Context Protocol) server for controlling Audacity through `mod-script-pipe`. Designed for hands-off LLM-driven audio pipelines — Claude Code (or any MCP client) can generate, process, and export audio entirely through tool calls with no manual Audacity interaction required.
## Features
- Connects to Audacity via `mod-script-pipe`
- Thread-safe — all pipe I/O is serialized through a lock and run off the event loop via `asyncio.to_thread`, so rapid sequential tool calls never interleave
- Generator tools work on empty projects — if no tracks exist the server writes a silent WAV to `/tmp`, imports it, and uses it as the generation target (Audacity's `Duration` scripting parameter is silently ignored; a selection is required)
- Full parameterized tools for `Export2`, `Import2`, `Select`, `GetInfo`, `SetTrackStatus`, `SetTrackAudio`, `OpenProject2`, `SaveProject2`
- Compound `generate_and_export` tool that handles an entire generate → select → export → cleanup cycle in one call
- Auto-detects pipe path suffix in `/tmp` (e.g. `.501`)
- Uses `stdio` transport (compatible with Claude Code, Claude Desktop, Codex)
## Requirements
- Audacity 3.x+
- Python 3.10+
- `mod-script-pipe` enabled in Audacity (see below)
## Install
```bash
git clone https://github.com/DaRealDaHoodie/mcp-audacity.git
cd mcp-audacity
./scripts/setup.sh
```
Manual setup:
```bash
python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install "mcp[cli]>=1.6.0" "httpx>=0.28.1"
```
## Enable mod-script-pipe in Audacity
1. Open Audacity.
2. Go to **Modules** preferences:
- **macOS**: `Audacity → Settings → Modules`
- **Windows/Linux**: `Edit → Preferences → Modules`
3. Set `mod-script-pipe` from `New` or `Disabled` to `Enabled`.
4. Restart Audacity.
Verify the pipes exist:
```bash
ls -l /tmp/audacity_script_pipe.to.* /tmp/audacity_script_pipe.from.*
```
If both files appear, Audacity is ready.
## Quick smoke test
```bash
# Audacity must already be running with mod-script-pipe enabled
./scripts/smoke_test.sh
```
## Run the server
```bash
./scripts/run.sh
```
Expected startup log:
```
Audacity MCP server starting up
Opened Audacity mod-script-pipe
Connected to Audacity mod-script-pipe
```
## Connect from Claude Code
Add to your MCP config (e.g. `~/.claude/claude_desktop_config.json` or via `claude mcp add`):
```json
{
"mcpServers": {
"audacity": {
"command": "/absolute/path/to/mcp-audacity/.venv/bin/python",
"args": ["/absolute/path/to/mcp-audacity/audacity_mcp_server.py"]
}
}
}
```
## Connect from Codex
```bash
codex mcp add AudacityMCP -- /absolute/path/to/mcp-audacity/.venv/bin/python /absolute/path/to/mcp-audacity/audacity_mcp_server.py
```
---
## Tool reference
### Generator tools
All generators work on empty projects. If no tracks exist, the server automatically creates a silent track of the correct `duration` in `/tmp`, imports it, and runs the generator against it (the generator replaces the silence). If tracks already exist, the generator applies to the current selection as usual.
> **Why the workaround?** Audacity's scripting API silently ignores the `Duration` parameter — generators always require an existing track with a selection. The server handles this transparently so you never have to think about it.
| Tool | Key parameters | Notes |
|---|---|---|
| `cmd_Noise` | `duration`, `noise_type` (White/Pink/Brownian), `amplitude` | |
| `cmd_Tone` | `duration`, `frequency`, `amplitude`, `waveform` (Sine/Square/Sawtooth) | |
| `cmd_Chirp` | `duration`, `start_frequency`, `end_frequency`, `start_amplitude`, `end_amplitude`, `waveform`, `interpolation` | Frequency sweep |
| `cmd_Pluck` | `duration`, `pitch` (MIDI note number), `fade` (Abrupt/Gradual) | |
| `cmd_DtmfTones` | `sequence`, `duration`, `amplitude` | Phone keypad tones |
| `cmd_RhythmTrack` | `tempo`, `beats_per_bar`, `duration` | Click track |
| `cmd_RissetDrum` | `duration`, `frequency`, `decay`, `cf`, `bw`, `noise`, `gain` | |
| `cmd_Nyquist` | `command` | Full Nyquist/Lisp DSP expression run against the selection, e.g. `(scale 0.5 s)` |
### Effect tools
All effects below are fully parameterized and apply without opening any dialog.
| Tool | Key parameters | Notes |
|---|---|---|
| `cmd_Amplify` | `ratio`, `allow_clipping` | `ratio=0.5` → -6 dB, `ratio=2.0` → +6 dB |
| `cmd_LoudnessNormalization` | `normalize_to` (LUFS/RMS), `lufs_level`, `rms_level`, `dual_mono` | `-23.0` LUFS = broadcast, `-14.0` LUFS = streaming |
| `cmd_Normalize` | `peak_level` (dBFS), `apply_volume`, `remove_dc_offset`, `stereo_independent` | Peak normalization — different from LUFS loudness |
| `cmd_Compressor` | `threshold`, `noise_floor`, `ratio`, `attack_time`, `release_time`, `normalize`, `use_peak` | Uses Audacity's LegacyCompressor internally |
| `cmd_Limiter` | `threshold_db`, `makeup_target_db`, `knee_width_db`, `lookahead_ms`, `release_ms` | Hard ceiling; use after compression |
| `cmd_Reverb` | `room_size`, `reverberance`, `hf_damping`, `wet_gain`, `dry_gain`, `stereo_width`, `wet_only` | All values 0–100 except gains (dB) |
| `cmd_Echo` | `delay` (seconds), `decay` (0.0–1.0) | Simple echo/repeat effect |
| `cmd_Repeat` | `count` | Repeats selection; total plays = count + 1 |
| `cmd_ChangePitch` | `percentage`, `use_high_quality` | Percentage shift e.g. 50.0 ≈ one octave up |
| `cmd_ChangeSpeed` | `percent` | Changes speed and pitch together |
| `cmd_ChangeTempo` | `percent`, `use_high_quality` | Changes tempo without affecting pitch |
| `cmd_TruncateSilence` | `threshold` (dBFS), `action`, `minimum`, `truncate`, `compress` | action: `"Truncate Detected Silence"` or `"Compress Excess Silence"` |
| `cmd_Paulstretch` | `stretch_factor`, `time_resolution` | Extreme time-stretch; `stretch_factor=10.0` = 10× longer |
| `cmd_BassAndTreble` | `bass` (dB), `treble` (dB), `gain` (dB), `link_sliders` | EQ adjustment, ±30 dB range |
| `cmd_ClickRemoval` | `threshold` (0–900), `max_spike_width` (0–40 samples) | Removes clicks and pops |
| `cmd_NoiseReduction` | _(no parameters)_ | Applies using last captured profile — see note below |
| `cmd_NoiseGate` | `threshold`, `mode`, `stereo_link`, `level_reduction`, `attack`, `hold`, `decay` | Gate or analyze mode |
| `cmd_HighPassFilter` | `frequency` (Hz), `rolloff` (dB6–dB48) | Cuts below frequency |
| `cmd_LowPassFilter` | `frequency` (Hz), `rolloff` (dB6–dB48) | Cuts above frequency |
| `cmd_NotchFilter` | `frequency` (Hz), `q` | Removes a specific frequency; higher Q = narrower notch |
| `cmd_AdjustableFade` | `fade_type` (Up/Down/SCurveUp/SCurveDown), `curve`, `units`, `gain0`, `gain1` | More control than plain FadeIn/FadeOut |
| `cmd_Tremolo` | `wave`, `phase`, `wet`, `lfo` | Amplitude modulation; lfo in Hz |
| `cmd_StereoToMono` | _(no parameters)_ | Mix stereo track down to mono |
Remaining effects with no meaningful automation parameters (FadeIn, FadeOut, Reverse, Invert, Repair, etc.) are available as no-parameter tools — they apply with Audacity's defaults.
#### `cmd_NoiseReduction` — manual profile required
Audacity's scripting API exposes **no parameters** for NoiseReduction. The two-pass profile capture cannot be automated. Workflow:
1. In Audacity, select a region containing only background noise
2. `Effects → Noise Reduction → Get Noise Profile`
3. Select the audio you want to clean
4. Call `cmd_NoiseReduction` — it applies the last captured profile
For fully automated noise cleanup, use `cmd_NoiseGate` instead (fully parameterized, no manual step).
### Macro tool
| Tool | Key parameters | Notes |
|---|---|---|
| `cmd_ApplyMacro` | `name` | Runs a saved Audacity macro by exact name. Use Macro Manager in Audacity to create macros that chain any sequence of effects. |
Macros are the most powerful tool for complex repeatable pipelines — build a chain once in Audacity, then fire it from Claude with a single `cmd_ApplyMacro` call.
### File tools
| Tool | Key parameters | Notes |
|---|---|---|
| `cmd_Import2` | `filename` (absolute path) | Import audio as new track |
| `cmd_Export2` | `filename`, `num_channels` | Format inferred from extension: `.wav` `.ogg` `.mp3` `.flac` `.aiff` |
| `cmd_OpenProject2` | `filename`, `add_to_history` | Open `.aup3` project |
| `cmd_SaveProject2` | `filename`, `add_to_history` | Save `.aup3` project |
### Selection and track tools
| Tool | Key parameters | Notes |
|---|---|---|
| `cmd_Select` | `start`, `end` (seconds), `track` (0-based), `track_count`, `mode` (Set/Add/Remove) | Combined time + track selection |
| `cmd_SelectTime` | `start`, `end`, `relative_to` | Time-only selection; relative_to: ProjectStart/ProjectEnd/SelectionStart/etc. |
| `cmd_SelectTracks` | `track` (0-based), `track_count`, `mode` | Track-only selection |
| `cmd_GetInfo` | `info_type` (Tracks/Clips/Labels/Envelopes/Boxes/Commands/Preferences/Selection), `format` | Inspect project state. Use `Type=Selection` to read current selection. |
| `cmd_SetTrackStatus` | `track` (0-based), `name`, `selected` | Rename or select/deselect a track |
| `cmd_SetTrackAudio` | `track` (0-based), `mute`, `solo`, `volume` (dB), `pan` (-1..1) | Set mix properties |
| `cmd_SetLabel` | `label` (0-based index), `text`, `start`, `end` | Edit an existing label's text or time range |
| `cmd_SetClip` | `track`, `at` (current start), `color` (Color0–Color3), `start` (new start) | Move or recolor a clip |
| `cmd_SetEnvelope` | `track`, `time`, `value` (0.0–2.0), `delete` | Add, move, or remove a volume envelope point |
| `cmd_BeatFinder` | `threshold` (0–100) | Detect beats and add labels |
| `cmd_LabelSounds` | `threshold`, `measurement`, `silence_duration`, `sound_duration`, `label_type`, `text` | Auto-label by sound/silence detection |
| `cmd_StereoToMono` | _(no parameters)_ | Convert stereo to mono |
### Preference tools
| Tool | Key parameters | Notes |
|---|---|---|
| `cmd_GetPreference` | `name` (key path) | Read any Audacity preference, e.g. `Quality/DefaultProjectSampleRate` |
| `cmd_SetPreference` | `name`, `value`, `reload` | Write any Audacity preference. `reload=True` applies immediately. |
Common preference keys for pipelines:
| Key | What it controls |
|---|---|
| `Quality/DefaultProjectSampleRate` | Default sample rate for new projects (e.g. `"44100"`, `"48000"`) |
| `Quality/DefaultProjectSampleFormat` | Bit depth: `"float"`, `"int24"`, `"int16"` |
| `AudioIO/PlaybackDevice` | Playback device name |
### Compound workflow tool
#### `cmd_generate_and_export`
Handles an entire generate-and-export cycle in one call. Useful for batch pipelines where you want to produce many audio files without orchestrating individual steps.
```
generator: Noise | Tone | Chirp | Pluck
duration: seconds (float)
output_path: absolute path including filename and extension
format is inferred from extension: .wav .ogg .flac .aiff
amplitude: 0.0–1.0
frequency: Hz (for Tone/Chirp/Pluck)
noise_type: White | Pink | Brownian (Noise only)
waveform: Sine | Square | Sawtooth (Tone/Chirp only)
num_channels: 1 (mono) or 2 (stereo)
```
Internally it runs: generate → SelectAll → Export2 → TrackClose. Because exactly one track is created per call, a single `TrackClose:` leaves the project empty and ready for the next iteration without opening a new Audacity window on each call.
Example prompt to Claude:
> "Generate 5 WAV files: white noise 2s, 440Hz sine 1s, 880Hz sawtooth 1s, pink noise 3s, and a plucked A4 1s. Save them to ~/sounds/ as noise_white.wav, tone_440.wav, tone_880_saw.wav, noise_pink.wav, pluck_a4.wav."
---
## Pipeline architecture
### How it works
```
Claude Code
│
▼ MCP tool calls (stdio)
audacity_mcp_server.py
│
▼ named pipe (mod-script-pipe)
Audacity 3.x
│
▼ file output
/your/output/directory/
```
### Important constraints
**One pipe, one process.** Audacity's mod-script-pipe creates a single pair of FIFOs. The MCP server opens them and holds them for its lifetime. No other process should open the same pipes while the server is running — if a standalone script also tries to read `pipe_from`, responses will be split between the two readers and both will get corrupted output. All Audacity interaction should go through this server.
**Commands are sequential.** The threading lock means every tool call waits for `BatchCommand finished` before the next command is sent. This is safe for rapid sequential calls but means there is no parallelism on the Audacity side by design.
**Audacity must be running.** The server does not launch Audacity. Start Audacity with mod-script-pipe enabled before starting the server.
### When to use Audacity vs Python + ffmpeg
For pure audio synthesis and format conversion, Python's `wave` module + `ffmpeg` is simpler and has no pipe constraints. Use this server when you need Audacity specifically:
| Need | Use |
|---|---|
| Synthesize tones, noise, sweeps | Either — Audacity via this server or Python + ffmpeg |
| Batch OGG/MP3 export + loudness normalization | ffmpeg (`loudnorm` filter) is easier |
| Noise reduction, click/crackle removal | Audacity — stronger algorithms |
| Nyquist scripting | Audacity only |
| Load an existing `.aup3` project and process it | Audacity only |
| LLM-driven batch generation of many files | `cmd_generate_and_export` compound tool, or Python + ffmpeg |
---
## Troubleshooting
| Symptom | Fix |
|---|---|
| `Failed to open Audacity pipes` | Confirm Audacity is running with mod-script-pipe enabled; check `/tmp/audacity_script_pipe.*` exists |
| `spawn uv ENOENT` | Use absolute paths in MCP config |
| `"Noise" requires one or more tracks to be selected` | This should not occur with the MCP tools — they auto-bootstrap a silent track on empty projects. If you see this, confirm you are calling `cmd_Noise` (not the raw `Noise:` bare command) and that the server was restarted after the latest changes. |
| `ApplyMacro` does nothing or errors | The macro name must match exactly as shown in Audacity's Macro Manager (case-sensitive). Verify the macro exists before calling `cmd_ApplyMacro`. |
| Nyquist command errors | Expressions must be valid Nyquist/Lisp. The `s` variable refers to the current selection. Test in Audacity's Nyquist Prompt first. |
| Commands time out or return empty | Another process is reading `pipe_from`. Stop it and restart the MCP server. |
| Tools behave inconsistently across calls | Ensure you are on the latest version; it serializes all commands through a lock and reads until `BatchCommand finished` |
## License
MIT
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues