MCP server for AI-native editable presentations: surgically edit slide components by stable ID, with local rendering and self-checking overflow.
SaferSkills independently audited deck-contract (MCP Server) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
An open standard + reference MCP server for AI-native editable artifacts. An AI edits one component of a deck surgically (by stable id) instead of regenerating the whole slide. No font drift (style is theme-token-only), no overflow (constraints + a render-and-check loop). First domain: presentations. Designed to extend to docs / resume / landing / LaTeX through the same contract.
Inference runs on the user's own AI subscription via MCP (the tool pays $0 for tokens); rendering is local (Chromium, $0 COGS).
template package (data)
-> deck.json immutable tree, stable string ids
-> apply(deck, ops[]) pure, transactional (all-or-nothing), inverse for free
-> compileHtml(deck) PURE, zero I/O -> deterministic HTML/CSS
-> render (Day 2) Playwright -> PNG + machine-readable issues[]
-> loop: model -> apply_patch -> render -> until issues = []
-> export PDFMCP, Playwright and git are swappable adapters at the edge; the core knows nothing about transport.
| package | role |
|---|---|
@deck/contract | Zod schemas, contract version, issues[] enum. Zero deps. |
@deck/core | immutable tree, stable id allocator, transactional apply+inverse, token validation |
@deck/compile | compileHtml(deck) — pure, deterministic deck → HTML/CSS |
@deck/renderer | LocalChromiumRenderer — headless Chromium → PNG + issues[] (overflow/out-of-bounds) |
@deck/loop | render-and-check loop with monotone gate + anti-oscillation + bounded iters |
@deck/loader | FileTemplateSource — resolve self-contained template packages from a folder/git |
@deck/mcp-server | 10 MCP tools over stdio (thin shell); handle-based state behind a DeckStore |
@deck/viewer | local interactive viewer — click to select, edit text, mark an "AI target"; live reload |
Dependency rule: everything depends on contract; contract depends on nothing. The domain ("slide", "title") must never leak into core/contract.
the schema boundary, so font drift has nothing to drift to.
spec: "deck-contract/1", tolerant reader, open node type.pnpm install
pnpm --filter @deck/renderer exec playwright install chromium # one-time
pnpm test # 38 tests: id stability, atomicity, inverse, token-only, determinism, render, convergence
pnpm preview # compile the sample deck -> examples/out/preview.html
pnpm render # surgical edit -> headless Chromium -> examples/out/slide-*.png
pnpm loop # run the fix loop on an overflowing deck -> monotone descent + before/after PNGs
pnpm agent # drive the MCP tools as a model would -> examples/out/deck-*.png + deck.pdf
pnpm viewer # open the interactive viewer on a working deck (http://localhost:4570)The point is not full AI generation. The source of truth is one deck.json, and both you and the model edit it through the same id-addressed ops:
pnpm viewer renders the live deck. Click any element to see itsstable id; double-click a title/heading to edit text in place; edits write back and reload live.
(via get_selection) reads exactly what you pointed at, then apply_patch changes it. With open_deck the model edits the very file the viewer shows, so its changes appear live in front of you.
A project-scoped .mcp.json is included. From a client that supports MCP, point it at the stdio server:
{
"mcpServers": {
"deck-contract": { "command": "npx", "args": ["tsx", "packages/mcp-server/src/bin.ts"] }
}
}Then the model has 10 tools: list_templates, load_template, open_deck, get_selection, get_outline, get_node, apply_patch, insert_block, render, export_deck. A typical turn: load_template (or open_deck to share the viewer's file) → get_selection/get_outline → apply_patch (surgical edit) → render (see the PNG + any overflow issues) → fix → export_deck (PDF). Inference runs on the client's own model; this server only edits structure and renders locally.
LocalChromiumRenderer: warm browser, network-blocked, fonts awaited,deterministic overflow / out-of-bounds measurement, PNG screenshots
proven to converge on golden fixtures with a deterministic solver (406→192→48→0px)
minimal-darkpackage, handle-based session state; full model-flow integration test green
get_selection + open_deck so user and model edit one shared deck.json live
MVP complete: an AI can load a template, surgically edit one component, render and self-check for overflow, and export a PDF — and the user can see the deck, edit elements directly, or point the AI at exactly the element they want changed — all on the client's own model.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.