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
missingAssetsis non-empty orwarningis 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
- Call
create_upload_linkwith the presentation id. - 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). curl -Tthe zip touploadUrl.- Call
get_presentation_files. WhenmissingAssetsis empty, giveviewUrl.
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.htmlin tool arguments on a local client - Call
list_presentationsto guess which deck to update, or before a first upload - Filter the folder by
html/css/jsand ignore images - Give
viewUrlwithoutget_presentation_filesafter the last upload
If create_upload_link is missing from the tool list, reload the Prezzly MCP server. See Troubleshooting.