# MCP server

Local Model Context Protocol adapter over the K2F SDK. Tool names and JSON schemas come from `engine/k2f_mcp/mcp_tools.json` (mirrored in `@openk2f/k2f` as `public/mcp_tools.json`).

> **MCP: stdio shipped** — run `cargo run -p k2f_mcp --release` from a k2f checkout. **Remote HTTP MCP is not shipped** ([project status](/status)). Without MCP, use [the K2F skill](/skills/k2f).

## Agent workflow

K2F MCP: copy an author directory (create) or open/markdown_to_k2f → Editor. insert_node/replace_text/set_role on Editor. Fill blanks with form_field nodes + replace_text; never draw ____ in body text. save writes .K2F (relock); export_pdf requires path. sign is not a tool.

## Tools (16)

Each tool wraps an existing SDK call. `sign` is not a tool.

### Open a session

Returns session_id and outline — never lock JSON.

| Tool | Description | SDK | Docs |
| :--- | :--- | :--- | :--- |
| `create` | Copy an author directory to dest_dir and open an Editor session. dest_dir must not exist. | `copy author dir + Editor.open_dir` | [k2f](/skills/k2f) |
| `open` | Open a local .K2F into an Editor session. Returns session_id + outline — never lock JSON. | `Editor.open(bytes)` | [k2f](/skills/k2f) |
| `markdown_to_k2f` | Convert Markdown to an Editor session (mutable). Returns session_id, outline, and report.warnings. | `markdownToK2f(md, opts)` | [k2f](/skills/k2f) |

### Read and validate

Semantic tree and integrity only; no layout coordinates.

| Tool | Description | SDK | Docs |
| :--- | :--- | :--- | :--- |
| `outline` | Editor tree summary: id, role, ~80 char preview, children ids. Requires Editor session. | `Editor.outline()` | [k2f](/skills/k2f) |
| `get_node` | Fetch one semantic node by stable id (agent JSON, no layout coordinates). | `getNode(id)` | [k2f](/skills/k2f) |
| `search` | Search node text; returns matching node ids. Requires Editor session. | `search(query)` | [k2f](/skills/k2f) |
| `validate` | Validate author source (semantic tree + theme vocab). Requires Editor session — use diff + save + verify before export. | `Editor.validate_package()` | [k2f](/skills/k2f) |
| `diff` | Semantic diff vs baseline at open/create time. Requires Editor session. | `diff()` | [k2f](/skills/k2f) |
| `verify` | Integrity banner and trust metadata for a .K2F path or open session with source_path. | `Viewer.banner() / status_code()` | [integrity](/integrity) |

### Edit the tree

Mutations on an open Editor session.

| Tool | Description | SDK | Docs |
| :--- | :--- | :--- | :--- |
| `replace_text` | Replace text on a Text/Math node (idempotent for same id+text). Requires Editor session. | `replaceText(id, text)` | [k2f](/skills/k2f) |
| `set_role` | Set semantic role (and optional variant) on a node. Role must exist in the package theme. | `setRole(id, role, variant?)` | [k2f](/skills/k2f) |
| `insert_node` | Insert a child under parent_id at index. node is a JSON object (not a string) with no x/y. Requires Editor session — not create(). | `insertNode(parentId, index, node)` | [k2f](/skills/k2f) |
| `delete_node` | Delete a node by id (cannot delete root). Requires Editor session. | `deleteNode(id)` | [k2f](/skills/k2f) |

### Save, export, publish

save and export_pdf require path; responses return paths and sizes, never file bytes.

| Tool | Description | SDK | Docs |
| :--- | :--- | :--- | :--- |
| `save` | Relock the session to an UNSIGNED .K2F at path (required). Strips signatures; appends changelog if diff is non-empty. Returns {path,size,banner} — never package bytes. Pass expected_content_hash for optimistic lock vs the hash at open. | `save()` | [k2f](/skills/k2f) |
| `export_pdf` | Export PDF from current lock to path (required). Unsaved Editor draws the old lock — save first. Returns {path,size} — never PDF bytes. | `exportPdf(bytes)` | [k2f](/skills/k2f) |
| `publish` | Relock session and POST to K2F publish API; returns /v/{appearance_hash}. Set dry_run=true to preview hashes without POST. Env K2F_PUBLISH_ORIGIN. | `POST /api/publish → /v/{appearance_hash}` | [k2f](/skills/k2f) |

## MCP resources

- `k2f://session/{session_id}`
- `k2f://session/{session_id}/node/{node_id}`

## Rules

- **No full lock JSON in context**. Return node JSON, banners, and file paths — never document.K2F.lock geometry or paint ops.
- **sign is human-gated**. sign is not an MCP tool. save writes UNSIGNED. Signing stays a separate human/org step.
- **Idempotent writes**. replace_text, save, and validate are safe to retry. The same (id, text) write must not append a second node.
