printcraft-automation
Agent control for PrintCraft: a headless tool table over the engine, and an opt-in MCP server.
- Layer: L7 (architecture §13), but headless. It depends on
engine,renderandorganize, never on a UI toolkit. - Status: 38 tools covering inspection, rendering, text, page edits, page labels, bookmarks, comments, form filling, password protection, metadata, undo/redo, save, combine, extract and split. Comment tools take geometry in the same top-left-origin points as everything else, and
comment_addcan mark text by searching for it (find). Planned next: form authoring and redaction tools as those features land, and MCP resources for page images. The running app's UI is driven separately, through theui.*control channel inprintcraft-ui-egui.
API
let mut a = Automation::new().with_root("/work")?; // optional: confine all paths
let doc = a.call("doc_open", &json!({ "path": "in.pdf" }))?; // Vec<Content>
tools() -> Vec<ToolDef> // name, title, description, input_schema, read_only, destructive, command
mcp::McpServer::new(a).serve(stdin, stdout)? // newline-delimited JSON-RPC 2.0
Content is Json(Value) or Png { data, width, height }. Errors are UnknownTool, InvalidArgs (the call didn't match the schema) or Failed (a readable message for the agent).
Conventions
- Tool names are
snake_case(page_rotate): MCP clients reject dots.ToolDef::commandlinks a tool to the registry id it automates (page.rotate), andcommand_listreports the link. - Pages and positions are 1-based. Rectangles are PDF points with the origin at the top-left of the displayed page.
- Unknown arguments are rejected, so typos fail loudly.
- Tools that change a document return its summary (
doc,pages,dirty,undo,redo, …). doc_closerefuses to drop unsaved changes unlessdiscard_changes: true.doc_savewrites atomically, incrementally in place, and in full for a new path.- With a root set, every read and write path must resolve inside it (symlinks and
..included).
MCP server
Opt-in only. Nothing starts it automatically, and it opens no port. It runs while printcraft-cli mcp [--root DIR] runs, normally launched by an agent from its MCP configuration. It stops when stdin closes. The CLI's mcp Cargo feature (on by default) compiles it out entirely when disabled.
Implemented: initialize (protocol 2025-06-18, 2025-03-26, 2024-11-05), ping, tools/list (with readOnlyHint/destructiveHint annotations) and tools/call (JSON results also returned as structuredContent; images as image/png). Tool failures come back as isError: true results, so the agent can read and recover from them.
Adding a tool
- Add the engine capability first, with its tests (the tool is a thin adapter).
- Add a
ToolDefinsrc/tools.rs: a precise description, the schema,ro()/destructive(), andcmd()if a registry command exists. - Handle it in
Automation::call, validating pages and positions with the existing helpers. - Add an end-to-end test in
tests/automation.rs.tool_table_is_well_formedchecks names, schemas and command links.