Files
photocraft/docs/mcp.md
T
Books 7198a94164 automation: accept absolute paths beneath the automation roots (#2176) (#2216)
doc_open, doc_save and the other automation file paths only took
forward-slash relative paths, so an agent passing C:/Users/me/a.png with
a C:/ root was refused. An absolute path is now compared with the
root's absolute path as text: if it lies beneath the root, the root's
components are stripped and the rest goes through the same checks as a
relative path and is opened through the same directory capability.
Nothing is resolved on the filesystem, so traversal, prefixes, device
names and link escapes are refused as before; absolute paths outside
the root, or with no root granted, are still refused.

Fixes #2176.
2026-10-10 05:53:23 -04:00

74 lines
4.6 KiB
Markdown

# MCP conventions
PhotoCraft follows the same conventions as FilmCraft #28. Start a headless session:
```sh
photocraft-cli mcp --automation-read-root /work/project --automation-write-root /work/project
```
Paths are relative to the corresponding root, or absolute paths beneath it; without a root that
filesystem authority is absent. Bridge mode uses `--bridge` and `--control-token-file` as
described in [development.md](development.md). UI tools require a running desktop app.
## Tools and resources
- `command_list`: discover engine ids, parameter docs and current enabled state; accepts
`filter` and `enabled_only`.
- `command_run`: `id`, optional `params` and `wait`. Command parameters remain engine-defined.
- `command_batch`: ordered `steps`, optional `stop_on_error`; one history step per command,
not an atomic transaction. Existing per-step results and reply budgets are preserved.
- `doc_inspect`: layer tree, history and selection; an empty session returns `document:null`.
- `render_preview`: bounded PNG content; `index` and `max_side` (default 1024, maximum 2048).
- `ui_inspect` and `ui_screenshot`: live app state/window in bridge mode.
Existing document/session/job/UI tools remain listed, including the documented
`doc_render_preview` spelling. There are no hidden legacy aliases. Every tool has a title
and all four annotation hints. Generic command/control tools conservatively advertise writes;
file saves may replace existing targets. Hints do not grant permission.
Unknown tool arguments return JSON-RPC `-32602`, naming the key, before execution. Batch
step envelopes are strict too. Nested engine `params` retain their command-specific handling.
Tool execution failures return `isError:true`. A worker panic becomes a tool error and the
existing poisoned-session recovery keeps serving. Invalid JSON lines receive `-32700` with
`id:null`; the next line is still processed.
Embedded Smart Objects support `command_run` with `layer.smartObjects.editContents` and
`layer.smartObjects.convertToLayers`, optionally targeting `params.layer`. Use
`layer.smartObjects.saveContents` in an opened contents document to update its parent in memory;
save nested contents from the inside outward, then `doc_save` the parent to a scoped path.
`doc_save` on a contents document exports that document rather than updating its parent.
No filesystem root is needed for the in-memory commands. External linked sources that require
a file read remain refused. See the [control policy](control-protocol.md#engine-commands)
for the shared restrictions.
`photocraft://document` and `photocraft://commands` return live JSON matching `doc_inspect`
and `command_list`. Resource reads are uncached; tool/resource catalogs are private and cached
for ten minutes. List/read responses include the MCP 2026-07-28 result/cache fields.
## Progress and cancellation
A direct headless `command_run` of `file.export.renderVideo` reports frame counts when
`_meta.progressToken` is present (a string or number). Notifications increase strictly,
are throttled to at most ten per second except completion, and include `total`. No token
means no progress notifications. Ping remains responsive while rendering.
```json
{"jsonrpc":"2.0","id":20,"method":"tools/call","params":{"name":"command_run","arguments":{"id":"file.export.renderVideo","params":{"dir":"frames","format":"png"}},"_meta":{"progressToken":"export-20"}}}
{"jsonrpc":"2.0","method":"notifications/cancelled","params":{"requestId":20}}
```
Create a document and timeline first (`doc_new`, then `timeline.create`). Export uses the
configured write root and creates `dir` beneath it. Filenames must be single components;
absolute paths, traversal and escaping symlinks are rejected. Existing target filenames
are refused, including symlinks, so a cancelled or failed job cannot replace an earlier export.
Only files actually created by this job are removed on cancellation, error or an escaped panic;
unrelated files and the destination directory remain. PNG sequences and animated GIF share
the engine renderer. The document and playhead are unchanged.
Cancellation suppresses the request response and stops at a frame boundary (the current
frame/encoding may finish first). Unknown request ids are ignored. Render Video stays a
synchronous command even with `wait:false`; other job-capable commands keep their existing
`jobs_list`/`jobs_cancel` behavior. Batch exports do not emit MCP progress or support per-step
MCP cancellation. Nested engine actions and bridge Render Video remain denied by the existing
ambient-filesystem policy; the new scoped writer is available for direct headless commands.