MCP actions — full catalog
The live catalog is always one MCP call away, and the codebase is the source of truth. This section explains how to navigate it, not enumerate every entry (the registry sits at ~130 actions today and adds / renames are continuous — recent additions include dsp.compile for FX-shape validation in the .dsp editor and builder.kind.describe now surfaces per-kind imports for the libfaust-wasm bundled libs).
The discovery dance
The pattern every MCP client uses (including the in-app Assistant) to find what it needs — say, to add reverb:
1. palette.list { search: "reverb" } → candidate actions
2. palette.describe { action_ids: ["master.fx.slot.add"] } → input_schema + examples
3. palette.run { action_id: "master.fx.slot.add", input: { … } }
For a quick "what categories exist":
palette.list {} ← returns category summaries
For everything:
palette.list { all: true } ← full catalog
Categories (today)
Actions cluster by category. The current set:
| Category | Roughly |
|---|---|
| DSP | Builder graph ops (~24 actions, hard-required module_id) + Faust DSP ops (dsp.run, DSP.param.*) |
| TRANSPORT | transport.play / stop / bpm.set |
| MIDI | Sequencer (~30 actions: tracks, slots, scenes, steps, key, progressions) + Keyboard (keyboard.note.on/off, .channel.set, .octave.set, .hold.set, .notes.clear, .state) + midi.note.play / midi.sequence.play / midi.sequence.stop + ports & diagnostics (midi.ports.list, midi.monitor.get) + midi.panic |
| AUDIO | Master volume / softclip / clip clear, audio device select, Master FX slots, Recorder + recordings, MixerTracks (mixer.tracks.* — set / create / delete / rename / reorder / attach_source / fx.add·remove·set) + legacy per-module strip params (mixer.set / mixer.clear) |
| ROUTING | Connection CRUD (routing.list / connect / disconnect / set), Source / Sink listing |
| MODULATION | LFO sources, mod-edge connect/disconnect, modulation.base.set |
| HUB | Search, install, publish, version upload, fork, star, item update / delete, account.delete (safety-railed) |
| KB | Search, doc.get, section list / get, scope set / clear, pack uninstall, reindex |
| PROJECT | List, current, switch, close, export, import, list project files (project.files), rename a project file (project.file.rename), delete a project file (project.file.delete) |
| FILE | Samples (samples.import / list / get / remove), lib mount / list, library list, editor source set / get / save |
| VIEW | Toggle rail / master / minimap panel |
| APPEARANCE | Theme set (Dark / Light / Cyberpunk / Auto) |
| SYSTEM | system.state snapshot (master / mixer / mixer_tracks / transport / chat / kb / auth / routing / midi-consumers / hub) |
| DEBUG | logs.get, activity.recent |
For a current count + breakdown:
actions:
- action_id: palette.list
input: {}
save_as: cats
label: "▶ Get the per-category counts"
Hot-path tools vs palette.run
The MCP transport publishes a curated subset (~22) of the highest-frequency actions as hot-path tools — they appear in the MCP client's tool list with their full schemas. The other ~108 actions live behind the palette.run meta-action.
The split exists because of the MCP 128-tool soft cap — Anthropic's API rejects more than 128 published tools in a single context. Current publishing decision: ~22 hot-path tools + palette.run + palette.list + palette.describe = 25 published, well under the cap.
Which actions are hot-path varies by build; the canonical list is the one the MCP client sees on connect.
Hard-required module_id rule
Every DSP-Builder action requires module_id as a first-class input. No fallback to "the active Builder." See FaustWave — AI Assistant § 3 Hard-required module_id on DSP-Builder actions for the rationale and the TOCTOU race it closes.
The sequencer has a documented exception — instance_id is optional with active-fallback. Grandfathered as a lower-frequency surface.
Dual-path vs mcpRun-only
Some actions have a run handler (the human-callable / Command-Palette path) plus an mcpRun handler (the AI-callable / MCP path). Some are mcpRun-only — the registry doesn't surface them in the Palette because they only make sense from the AI side.
Examples:
- Dual-path:
transport.play(UI button + MCP),recorder.toggle(Topbar Widget + MCP), most user-facing toggles. - mcpRun-only:
builder.graph.get(no UI surface for "show me the graph as JSON" — that's the canvas),kb.search(the assistant's grounding tool, not a user gesture).
Friendly error strings
Most actions return strings (success or error) rather than throwing. The Activity log shows the string in the result field for both — handler-returned error strings still count as outcome: completed. Real exceptions are outcome: failed with the message in error.
This is the "AI-friendly errors" convention — the model can read the string back, self-correct, retry. Examples:
"Module id is required. Available Builders: builder-abc, builder-xyz""dsp.polyphonic.set needs a non-negative integer voices count, got string: 'eight'""Theme set to cyberpunk."
Where the real catalog lives
For a precise + current listing, query the registry directly:
palette.list { all: true }
It returns id + title + category + description for every registered action. Pipe through palette.describe { action_ids: [...] } for the input schemas.
The codebase organisation mirrors the categories — actions live in packages/<extension>/src/commands/*.ts or lib/commands.ts. Each buildXxxCommands(api) returns the ActionDef[] for that extension. The shell aggregates them at extension activation.
Where to go from here
- FaustWave — AI Assistant § 2 — the Command Palette (human surface to the same registry).
- FaustWave — AI Assistant § 1 — the in-app AI surface.
- FaustWave — AI Assistant § 3 — the external-client (MCP) surface.