# MCP server `deckcraft-cli mcp` runs a Model Context Protocol server on stdio. By default it drives its own headless engine (no window); with `--connect PORT` it drives a running DeckCraft started with `--control PORT`, so an agent and a person can work on the same deck. `--sample` opens the sample deck. Connected mode accepts only newline-terminated replies of at most 16 MiB (including the newline), with the current request's numeric `id`, a boolean `ok`, and either `result` on success or a string `error` on failure. CRLF is accepted. Invalid replies close the connection and report that the command may or may not have run; they never cause a replay. Check the document before retrying a mutation. Before sending another request, unsolicited bytes in the reader's buffer or on the socket cause a fresh connection to be opened. Large image replies must fit this budget; render to a file or use a smaller scale when necessary. Regression coverage for #718 lives in `crates/mcp/src/backend.rs`: synthetic loopback peers test reply correlation, envelopes, framing, the size cap and buffered unsolicited bytes, alongside the lost-reply and reconnect tests. ```json { "mcpServers": { "deckcraft": { "command": "deckcraft-cli", "args": ["mcp", "--connect", "7990"] } } } ``` ## Confining file access ```sh deckcraft-cli mcp --automation-read-root /work/project --automation-write-root /work/project/out ``` ```json {"mcpServers": {"deckcraft": {"command": "deckcraft-cli", "args": ["mcp", "--automation-read-root", "/work/project", "--automation-write-root", "/work/project/out"]}}} ``` The two flags (VectorCraft, PhotoCraft 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_presentation` and `file.open`, and `insert_picture`, `insert.picture`, `picture.change`, `insert.audio` and `insert.video` with a `path`. Pictures, audio and video are copied into the deck when they are inserted, so playing them later reads nothing from disk. - Every file a command writes must lie inside the **write root**: `save_presentation`, `export` (every format, and every slide of an image export), `file.save`, `file.saveAs`, `file.export`, and `render_slide` with a `path`, plus the `.saving` temporary file a save goes through. - 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.pptx` or `automation filesystem access is not granted: write authority is absent: /work/project/out/x.pptx`. - The roots must be existing folders; a missing one stops the server with an error. Each flag is given once (`--flag