Reference
Using Soundbox from an AI agent
The tools an agent gets when it connects to Soundbox over MCP.
Soundbox exposes its generation pipeline over MCP. An agent can generate sound effects, music and speech as part of a larger task, and arrange longer pieces on a timeline it can return to later.
The MCP server runs inside the main Soundbox process at
http://127.0.0.1:17494/mcp. The server must be running. There is no
separate daemon to start.
Connecting
HTTP (preferred)
{
"mcpServers": {
"soundbox": { "type": "http", "url": "http://127.0.0.1:17494/mcp" }
}
}Claude Code:
claude mcp add --transport http soundbox http://127.0.0.1:17494/mcpThe URL has no trailing slash. Soundbox rewrites /mcp to the mounted path
internally, so clients that don't follow 307 redirects on POST work.
stdio
For clients that only speak stdio. The bridge is a thin proxy onto the running server. It does not load models, so there is never a second copy of a model on your GPU.
{
"mcpServers": {
"soundbox": {
"command": "node",
"args": ["/absolute/path/to/soundbox/server/dist/mcp/stdio.js"]
}
}
}Use the absolute path to the script. npx soundbox-mcp does not resolve
because the package is private. npm install links a soundbox-mcp bin, but
only into the checkout's own node_modules/.bin, which is not on the PATH
your editor spawns an MCP server with. Both short forms fail with "command not
found".
server/dist/mcp/stdio.js exists only after npm run build (or
npm run build --workspace server); a fresh clone does not have it.
The Agents page prints this line with the path resolved for the install you are running. Copy it from there.
The bridge covers six tools: generate, enhance_prompt, list_models,
list_sounds, get_sound and delete_sound. For separate, speech,
stories and arrangement, use the HTTP transport.
Set SOUNDBOX_URL if the server listens somewhere other than
http://127.0.0.1:17494.
Tools
Twenty-one tools in four groups: sounds, voices, stories, arrangement. The
authority is server/src/mcp/server.ts: the MCP_TOOLS table for names and
descriptions, and the zod inputSchema on each registerTool call for
arguments. Where this file and that one disagree, that one is right.
Sounds
soundbox.generate
Generates one or more sounds and saves them to the library. Blocks until the audio is written to disk, which can be seconds to a minute depending on model and length.
| Argument | Type | Default | Notes |
|---|---|---|---|
prompt |
string | — | Describe material, action and space |
duration_s |
number | 5.0 | 0.5–30, clamped to the model's max |
model |
string? | loaded model | Falls back to the first installed one |
negative_prompt |
string? | — | Ignored by models that don't support it |
seed |
int? | random | For reproducibility |
variations |
int | 1 | 1–4 distinct takes |
tags |
string[]? | — | Library tags |
lyrics |
string? | — | Words for a lyrics-conditioned music model to sing |
source_sound_id |
string? | — | Edit an existing sound instead of rendering fresh |
edit |
string? | — | extend / cover / repaint, paired with source_sound_id |
Returns each sound with an absolute filesystem path, which the agent can pass to ffmpeg or copy into a project.
lyrics and the edit family only work on models that declare them
(supports.lyrics, supports.extend, supports.cover in list_models).
Other models ignore these fields silently.
soundbox.separate
Splits a library sound into its stems (vocals, drums, bass, other), each saved
as its own sound with its own absolute path. Blocks until the audio is on
disk. Needs a separation model installed (task: "sep" in list_models).
| Argument | Type | Default | Notes |
|---|---|---|---|
sound_id |
string | — | The library sound to split |
model |
string? | installed separator | Prefers one already loaded |
stems |
string[]? | all | Which stems to keep, e.g. ["vocals"]. A name nothing answers to is reported back, not dropped |
rest |
discard / merge |
discard |
What happens to the stems not named. merge sums them into one "rest" sound (the original minus what you took out). Ignored when stems is omitted |
soundbox.enhance_prompt
Rewrites a vague prompt ("scary sound") into one or more concrete ones. Takes
prompt, n (1–5), category (sfx / music), lyrics, and model. Pass
the id you intend to generate with and the rewrite follows that model's
prompting conventions.
Requires the local prompt assistant. When it is off, the tool returns a plain-text explanation instead of an error; surface that reply to the user.
soundbox.list_models
Models with status and licence, including commercial_use (yes / no /
conditional). Call it before generating anything for a commercial project.
For a text-to-speech model it also returns delivery: the parameters that
model accepts, each with its range and default, read from audio.cpp's own
parameter table. Use these names. audio.cpp accepts unknown options silently,
so a name taken from a model card raises no error and has no effect. A model
with no delivery list has no such parameters; only its text and voice
control the output.
soundbox.list_sounds / soundbox.get_sound / soundbox.delete_sound
Search and manage the library. list_sounds takes q, tag and limit;
searching before generating is usually faster than regenerating. get_sound
takes a sound_id and returns the one sound with its absolute path.
delete_sound takes a sound_id and permanently removes the row and the
file on disk.
Voices
soundbox.generate does not produce speech. Use the voice tools below.
soundbox.list_voices
No arguments. Returns the saved voices a script can be read in. Call it before writing a script so lines are cast to real voice ids.
soundbox.speak
One read, saved to the library. Takes lines (1–200 objects of text,
voice_id, speaker; several with different voice_ids make a dialogue),
model, gap_s (silence between lines, default 0.4), name, and delivery.
Blocks until the audio is written.
speak produces one finished WAV that cannot be edited afterwards. Use a story
for anything you want to keep, re-read or rearrange.
Stories
A story is a persistent script. Each line has a position in time, can be voiced individually, and stays in the library after the conversation ends.
soundbox.create_story
Takes title and delivery. Returns a summary with a story_id and an
open_in_studio URL. Every story tool returns this summary.
soundbox.list_stories / soundbox.get_story
list_stories takes limit (1–200, default 20), most recently worked on
first. get_story takes a story_id and returns every line: text, voice,
track, start, and whether it has been voiced yet. The summary the other tools
return omits the lines; use get_story to read them.
soundbox.add_lines
Takes story_id and lines (1–200). Each line is a spoken line, a pause of
duration_s seconds, or an existing library sound_id placed on the
timeline. track_index picks the lane and start_s the position. Omit
start_s to append after that track's last clip.
soundbox.update_line
Takes line_id plus whatever you are changing: text, speaker, voice_id,
track_index, start_s, muted, gain_db, duration_s (how much of the
clip plays), trim_start_s (how far into the source it begins), delivery.
Changing the words or the delivery does not re-read the line. The existing audio stays until the line is voiced again.
soundbox.speak_story
Takes story_id, model, and regenerate (re-read lines that already have
audio, default false). Reads every silent line in its assigned voice, one at a
time. This is the slowest tool: a forty-line script is forty reads.
soundbox.delete_line / soundbox.split_line
delete_line takes a line_id and removes it from the story; the audio it was
using stays in the library. split_line takes line_id and at_s (seconds
into that line's own audio) and produces two clips. The text stays with the
first clip, since Soundbox cannot tell which words fall on each side of the cut.
soundbox.export_story
Takes story_id. Mixes the whole arrangement down to one sound, honouring
where each clip sits, its trim, its gain and whether it is muted. Blocks,
and returns the resulting sound with an absolute path.
Arrangement
soundbox.open_in_studio
Takes sound_id, separate (split into stems first, default true), stems
(which ones get a track; omit for all) and rest (discard or merge the
ones you didn't name). Lays a library sound out on a timeline. Reuses stems the
sound already has instead of separating it again.
soundbox.mix_track / soundbox.remove_track
mix_track takes story_id, track_index and any of name, muted,
soloed, gain_db. These settings apply to the lane as a whole. With any
track soloed, only soloed tracks are heard. remove_track takes
story_id and track_index and deletes the lane and everything on it;
lanes above slide down. Call get_story first if you are not certain what is
on it.
Delivery
Set how a line is performed with delivery, not in the text. Writing
(whispering) into a line makes the model say the word "whispering" aloud.
Pass delivery at the level it applies to:
| Where | Applies to |
|---|---|
soundbox.create_story |
Every line in the story that doesn't override it |
soundbox.add_lines |
One line, set as it is written |
soundbox.update_line |
One line, afterwards. {} puts it back on the story's |
soundbox.speak |
The whole one-off read |
The narrowest level wins: a line's own delivery overrides the story's. Changing a delivery does not re-read anything; voice the line again to hear it.
Watching what your agents do
Open the Agents page in the app (/#/agents) to see every client that has
connected: which agent, what it called, whether it worked, how long it took,
and every sound it produced, updated live. It also shows the endpoint and
stdio command above, and the bundled skills below.
Every call the server handles is:
Attributed. The MCP handshake's
clientInfo(name + version) is captured automatically. There is no header to add and no auth. Sounds an agent generates are tagged with that identity (Sound.source = "mcp",Sound.client = "claude-code 2.1.0"), and the Library can filter to what agents made.Logged. One line per call in the server's log (
grep mcp ~/.soundbox/soundbox-17494.log, or whatever port you run on), and persisted toGET /api/mcp/calls/GET /api/mcp/statusfor the app or your own tooling to read.Optionally exported. OpenTelemetry export is built in, with nothing extra to install. Point it at a collector:
{ "otel_endpoint": "http://localhost:4318" }via
PATCH /api/settings, or setOTEL_EXPORTER_OTLP_ENDPOINTin the server's environment (that env var wins). Each call becomes a span carrying the client, session, tool, model and resulting sound ids on standard OTLP/HTTP: traces to<endpoint>/v1/traces, metrics to<endpoint>/v1/metrics. Works with Jaeger, Tempo, Honeycomb, the OTel Collector, or anything else that speaks OTLP.
Skills
Soundbox ships agent skills under server/skills/:
soundbox-sfx (prompting technique, tool usage), soundbox-sound-pass
(inventorying and generating every sound event a whole project needs) and
soundbox-voice-story (writing, voicing and arranging spoken audio as a
story). They tell a connected agent how to prompt and call these tools.
Install them once per machine:
soundbox skills install # -> ~/.claude/skills/
soundbox skills install --target cursor # -> ~/.cursor/skills/
soundbox skills list # see what's bundled/installedor click Install skills on the Agents page, which calls
POST /api/mcp/skills/install. Re-running overwrites, so reinstall after
upgrading Soundbox to keep them current.
Notes for agent authors
Generation is serialised. One GPU, one job at a time. Five parallel
generate calls are queued and run one after another. Use variations for
several takes of the same idea.
No model loaded is a normal state. If nothing is installed, generate
returns an error telling the user to install one from the Models screen.
Surface it instead of retrying.
Prompt style matters more than parameters. These models respond to physical description (material, action, space) and ignore mood words. "Scary sound" produces noise. "Low metallic groan of a ship's hull under pressure, distant, reverberant" produces something usable. Several short clips layered in an editor usually sound better than one long generation.
Licences are per-model and some forbid commercial use. If the user's
project is commercial, prefer a model whose commercial_use is yes.