mirror of
https://github.com/storytold/soundcraft.git
synced 2026-10-14 14:26:46 -04:00
Docs: document --automation-read-root and --automation-write-root for mcp
This commit is contained in:
1 parent
a9fa027528
commit
719fd909ee
1 file changed
+68
+68
@@ -6,6 +6,7 @@ Claude and other agents can make music with it.
|
||||
```sh
|
||||
soundcraft-cli mcp # headless engine (no window, no audio device)
|
||||
soundcraft-cli mcp --demo # headless, starting from the demo session
|
||||
soundcraft-cli mcp --automation-read-root DIR --automation-write-root DIR # headless, confined to folders
|
||||
soundcraft --control 7801 & # the desktop app…
|
||||
soundcraft-cli mcp --connect 7801 # …driven over MCP: same tools plus screenshots and clicks
|
||||
```
|
||||
@@ -16,6 +17,73 @@ Claude Code:
|
||||
claude mcp add soundcraft -- soundcraft-cli mcp --demo
|
||||
```
|
||||
|
||||
## Confining file access
|
||||
|
||||
```sh
|
||||
soundcraft-cli mcp --automation-read-root /work/project --automation-write-root /work/project/out
|
||||
```
|
||||
|
||||
```json
|
||||
{"mcpServers": {"soundcraft": {"command": "soundcraft-cli",
|
||||
"args": ["mcp", "--automation-read-root", "/work/project", "--automation-write-root", "/work/project/out"]}}}
|
||||
```
|
||||
|
||||
The two flags (VectorCraft and the other Craft apps take the same ones, so one client config
|
||||
works across the suite) keep the agent to the folders you give it:
|
||||
|
||||
- Every file a command reads must lie inside the **read root**: `open_session`, `session.open`,
|
||||
`import_audio` and `file.import_audio`, `file.import_midi`, `file.import_video`,
|
||||
`file.import_clip_groups`, `file.import_session_data`, `track.load_preset` and
|
||||
`mix.sampler_load`. The media a session file names is read too, so an opened session whose
|
||||
audio paths lead outside the read root loads without that audio and lists it under `missing`.
|
||||
- Every file a command writes must lie inside the **write root**: `save_session`, `session.save`,
|
||||
`session.save_as`, `session.save_copy`, `session.save_template`, `bounce_mix` and
|
||||
`file.bounce_mix`, `file.bounce_stems`, `file.export_clips`, `file.export_midi`,
|
||||
`file.export_session_text`, `file.export_selected_tracks_as_session`, `file.export_sibelius`,
|
||||
`file.send_to_sibelius`, `file.print_score`, `file.export_clip_groups` and
|
||||
`track.save_preset`, together with what a session save writes beside the session file
|
||||
(`Audio Files/`, `Backups/`) and its temporary file. A score command given no `path` writes to
|
||||
the temp folder, which is outside the write root unless you made it the root, so it is refused.
|
||||
- Read and write access are separate. Give the same folder twice for both; a root left out grants
|
||||
none of its access (with only `--automation-read-root`, nothing can be written to disk). Without
|
||||
either flag nothing changes.
|
||||
- A path is made absolute against the server's working directory, then its links are followed: a
|
||||
file (or folder) link that leads out of a root is outside it. For a file that doesn't exist yet,
|
||||
its nearest existing folder's links are followed and the rest must be plain names, so `..` below a
|
||||
folder that doesn't exist is refused, as is a link that leads nowhere (writing through it would
|
||||
create its target). The result is compared with the root by whole folder names: `/work2/x` is not
|
||||
inside `/work`. On Windows case is ignored, UNC paths (`\\server\share\...`) are resolved like
|
||||
drive-letter ones, and device names (`CON`, `NUL`, `COM1`...) are refused.
|
||||
- A refused path is an ordinary tool error the agent can read and correct, for example
|
||||
`automation path rejected: outside the write root /work/project/out: /etc/x.wav` or
|
||||
`automation filesystem access is not granted: write authority is absent: /work/project/out/x.wav`.
|
||||
A refused save path is reported as refused, never as "already exists".
|
||||
- The roots must be existing folders; a missing one stops the server with an error. Each flag is
|
||||
given once (`--flag <dir>` or `--flag=<dir>`), and a misspelled `--automation-...` flag is an
|
||||
error rather than an unconfined server.
|
||||
|
||||
The flags confine the in-process server, so `--connect` together with them is an error: the server
|
||||
would otherwise talk to an app that isn't confined. SoundCraft's desktop app has no equivalent flags
|
||||
yet, so a running app (`soundcraft --control`) is not confined. `--demo` is the operator's own
|
||||
choice and is built before the roots apply.
|
||||
|
||||
Playback and bounce need no check of their own. SoundCraft decodes audio into the session when it
|
||||
enters it (import, open, sampler load), so rendering reads nothing from disk afterwards. Movies are
|
||||
the exception: a session only references them by path and the desktop app decodes pictures from
|
||||
that file, but the headless server never does, and the movie's path is checked when it is imported
|
||||
and when a session naming it is opened.
|
||||
|
||||
What the roots do not cover: commands that take no path still read and change the open session,
|
||||
and `inspect_session` returns it. Plug-in discovery scans the system's plug-in folders and loads
|
||||
plug-in binaries, which are fixed locations and native code, not agent paths. Recording is only
|
||||
reachable in the desktop app. Anything that reads or writes a path goes through one place in the
|
||||
engine (`io::read_file`, `io::write_file` and the helpers beside them in `crates/engine/src/io.rs`);
|
||||
a test keeps the rest of the engine from touching the file system on its own.
|
||||
|
||||
The checks hold for every thread of the server process. A path is checked, then opened: another
|
||||
program that swaps a link in between can still win that race, so the roots keep an agent to the
|
||||
files it was given rather than guarding against other software on the computer.
|
||||
|
||||
## Tools
|
||||
|
||||
| Tool | Purpose |
|
||||
|
||||
Reference in new issue
Block a user