Skip to content
Documentation

Publish and update a deck

Last updated: 2026-09-05

Call create_presentation once for a new deck. Do not list the library first. Do not upload a stub.

kind is presentation (slides) or dashboard (one scrollable page). It is not inferred from the HTML. See Slides and dashboards.

Never put image or font bytes in MCP tool arguments.

Chat clients (Claude.ai, no disk)

Send files with one self-contained index.html. Put CSS and JS in that HTML. Use https image URLs or small data URIs. Do not build a zip in the browser. add_files with url can pull a remote asset.

create_presentation({ "title": "Q1 Review", "kind": "presentation", "files": [{ "path": "index.html", "content": "<!doctype html>..." }] })

Then give the user viewUrl. If missingAssets is not empty, fetch those URLs with add_files or tell the user the deck is incomplete.

Local clients (Cursor, Claude Code, files on disk)

Call create_presentation with title and kind only. Do not paste index.html or binaries into the tool.

create_presentation({ "title": "Q1 Review", "kind": "dashboard" })

Read uploadUrl. Prefer one zip of the folder (the server unwraps a single top-level folder). Use a zip when any path has spaces or non-ASCII characters (curl -T does not encode the URL).

cd <dir> && zip -r /tmp/deck.zip . -x '.git/*' '.cursor/*' '.agents/*' 'node_modules/*' 'skills-lock.json' '*.zip' '*.code-workspace'
curl -sS -T /tmp/deck.zip -H 'Content-Type: application/zip' -w '\n%{http_code}\n' "<uploadUrl>"

Or upload index.html first, then each remaining ASCII path:

curl -sS -T index.html "<uploadUrl>index.html"
curl -sS -T "assets/hero.webp" "<uploadUrl>assets/hero.webp"

curl -T to uploadUrl (trailing slash) is fine: the server unpacks a zip even if curl appends deck.zip to the path.

Read missingAssets from each JSON body. Repeat until the list is empty. If uploadUrl expired, call create_upload_link and continue. Then call get_presentation_files once and give the user viewUrl.

Warning: Do not tell the user the upload is done while missingAssets is non-empty or warning is set. Do not flatten a zip (zip -j). Keep relative paths.

New deck vs revision

create_presentation makes a new deck. add_revision / a zip to create_upload_link is a new version of the same deck. History, share links, and comments stay.

Use a revision when the user named the deck, pasted a Prezzly URL or id, or said update / next revision. Use a new presentation when they asked for another deck or a separate copy. If you are not sure, ask.

Local edit

  1. Call create_upload_link with the presentation id.
  2. Zip what changed. A text-only tweak can be a zip of index.html. Previously uploaded assets still referenced by the HTML are reused (reusedAssets).
  3. curl -T the zip to uploadUrl.
  4. Call get_presentation_files. When missingAssets is empty, give viewUrl.

A single PUT of index.html to an existing deck is rejected (400). A zip to uploadUrl is a new revision.

Chat edit

add_revision with files containing the real index.html. Assets still referenced are reused. Never send a placeholder to obtain uploadUrl. Use create_upload_link for that.

add_files appends small text or a remote https URL. Existing paths are rejected; zip a new revision to replace them.

restore_revision rolls back. Revisions are history.

Upload responses

Status Body signal What to do
200 missingAssets non-empty Upload the listed paths. Not done yet.
200 missingAssets: [] Call get_presentation_files, then give viewUrl.
200 warning set Act on the warning before finishing.
401 create_upload_link hint Token expired. Call create_upload_link, retry.
402 code: plan_limit Storage or upload cap. Tell the user; do not retry.
409 Upload index.html or a zip first Empty deck. Upload HTML or a zip before assets.
409 files + missingAssets listed Path exists with different bytes. Replace via a zip / add_revision.
400 index.html cannot be added this way Replace HTML with a zip (local) or add_revision files (chat).

Re-curl -T of the exact same bytes is safe: it returns 200, not 409.

Add -w '\n%{http_code}\n' so you see the status. curl -sS prints the JSON body on 4xx, so read the body, not just the exit code.

Do not

  • Upload a stub, placeholder, or empty shell and promise to revise later
  • Put image, font, zip, or a local index.html in tool arguments on a local client
  • Call list_presentations to guess which deck to update, or before a first upload
  • Filter the folder by html/css/js and ignore images
  • Give viewUrl without get_presentation_files after the last upload

If create_upload_link is missing from the tool list, reload the Prezzly MCP server. See Troubleshooting.