MCP & CLI
MCP Server
Connect Claude Desktop or Claude Code to heydecks. Build, edit, and publish decks in natural language.
The heydecks MCP server lets Claude (or any MCP-aware agent) create and edit decks in your workspace. The server lives at https://heydecks.com/mcp. Sign in with OAuth (the host opens a browser, no token to paste) or use a personal access token. Every action runs as you: same workspace, same brands, same decks.
The endpoint speaks JSON-RPC 2.0 over HTTP. One POST per call (or a batched array). No SSE or long-polling.
#Two ways to connect
- OAuth (recommended). Point a remote-MCP-capable host at
https://heydecks.com/mcpand sign in with heydecks in the browser: nothing to paste. The host runs the OAuth flow and heydecks issues a scoped token tied to your account, refreshed automatically. - Access token. Generate a personal
mcp_token in the dashboard and send it as a Bearer header. Best for headless setups and CI.
The fastest path either way is the CLI: npx heydecks install wires up Claude Desktop, Claude Code, and Cursor for OAuth in one command (add --token mcp_xxx to use a token instead).
#Connect with OAuth
Cursor — add the remote server; Cursor runs the sign-in for you:
{ "mcpServers": { "heydecks": { "url": "https://heydecks.com/mcp" } } }Claude Code — connect over HTTP and authenticate in the browser:
claude mcp add --transport http heydecks https://heydecks.com/mcpClaude Desktop — it speaks stdio only, so bridge through mcp-remote, which handles the browser sign-in:
{ "mcpServers": { "heydecks": { "command": "npx", "args": ["-y", "mcp-remote", "https://heydecks.com/mcp"] } } }Restart the host; the first call opens a browser to authorize heydecks. Under the hood this is standard OAuth 2.1 (PKCE, dynamic client registration) with Clerk as the authorization server.
mcp-remoteprerequisites (both connection methods below).mcp-remoteruns throughnpx, so you need Node.js installed. On macOS, Claude Desktop launches as a GUI app and does not inherit your shellPATH, so a bare"npx"can fail with "command not found." If it does, put the absolute path tonpxin"command"— find it in a terminal withwhich npx(typically/opt/homebrew/bin/npxon Apple Silicon,/usr/local/bin/npxon Intel Macs).
#Connect with a token
#Mint a token
- Sign in — Go to heydecks.com and sign in.
- Create a token — Open Account settings → MCP access → New token. Name it (e.g. "Claude Desktop"), then copy the plaintext — it is shown once.
- Revoke when done — Revoke at any time from the same page. Revocation takes effect on the next call.
heydecks stores only sha256(token) plus an 8-character prefix for recognition. Tokens are scoped to your user — they never grant cross-workspace access.
#Claude Desktop
The current Claude Desktop build only accepts command-based (stdio) servers in claude_desktop_config.json — it does not take a remote HTTP URL directly, and it rejects the transport: { … } (and the flat type/url/headers) shapes with "Skipped invalid MCP server config entries." The built-in "Add custom connector" UI only does OAuth, not a static bearer token. So for token auth, bridge through mcp-remote and pass the token as a header.
Open Settings → Developer → Edit Config and paste:
claude_desktop_config.json
{
"mcpServers": {
"heydecks": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://heydecks.com/mcp",
"--header",
"Authorization: Bearer mcp_…your_token…"
]
}
}
}Restart Claude Desktop. heydecks appears in the MCP servers panel. (See the mcp-remote prerequisites above — Node.js, and on macOS the absolute path to npx.)
If you would rather not manage a token, use the OAuth setup above instead — the browser sign-in needs no config file editing beyond the one mcp-remote line.
#Claude Code
claude mcp add --transport http heydecks https://heydecks.com/mcp \
--header "Authorization: Bearer <token>"Replace <token> with the plaintext from the dashboard.
#Tools
The MCP is a structured deck store, not a generator. You (the connected model) design the deck and write every word; these tools persist what you send. There is no server-side AI writing copy, so the deck sounds like you. A deck costs 100 credits, the same whether you build it in the dashboard, over the REST API, or over MCP.
The recommended flow: call list_slide_templates (and list_slide_types) to learn the building blocks, decide the structure and content yourself, then create_deck followed by add_slides to build it in one call, and publish_deck when ready. The initialize handshake returns slide-selection and length guidance to help you pick well.
| Tool | Purpose |
|---|---|
list_slide_templates ★ start here | Returns every available template with its content field schema (each field's key, label, type, max length, allowed values). Call this first so you know what shape each slide expects. |
list_slide_types | Workspace-defined custom slide types with their layout and field schema. Reference them as custom:<id>. |
list_brands | Lists brands in your workspace — palette, typography, active flag. |
list_decks | Lists your decks, slugs, status, and public URL (if published). |
get_deck | Returns a single deck with every slide and its content. |
export_deck | Returns a short, ready-to-download link (heydecks.com/s/<code>) for a deck as PDF or PPTX — no dashboard visit. Scoped to the deck and format, expires (default 30 min, up to 24h via ttl_minutes). Works on drafts. PDF on any plan; PPTX (native editable PowerPoint) needs Solo or higher. |
preview_deck | Returns a short link (heydecks.com/s/<code>) to a PNG preview of one slide, so you can see how a deck looks instead of building blind. Pass slide (0-based) or omit for the cover. Deck-scoped, expiring; works on drafts. Free on every plan. |
create_deck | Creates a new deck. Pass slides (same shape as add_slides) to fill it in the same call, replacing the placeholder cover/close; otherwise it ships with a title cover and CTA close to fill later. Optional brand_id and locale (en or de). Costs 100 credits. |
add_slides ★ | Adds many slides at once — the fastest way to build a deck you have designed. slides is an ordered array of { slide_type, content, notes? }. Pass replace: true to make it the deck's complete slide list (drops the placeholder cover/close, so include your own). |
append_slide | Adds a single slide to a deck. slide_type must come from list_slide_templates; content must match that template's field schema. Appends at the end by default, or pass index / after_slide_id to place it, and notes for speaker notes. |
update_slide | Changes a slide's content fields. Pass only the fields to change, merged on top of current content. Optional notes sets speaker notes. |
delete_slide | Removes a slide permanently. |
reorder_slides | Reorders slides by passing the full list of slide ids in the new order. |
update_deck | Updates deck title, slug, visibility, password, locale, or brandId. visibility is access control (who may open the deck once live); publishing is separate — use publish_deck / unpublish_deck. |
publish_deck | Makes the deck live at https://heydecks.com/d/<slug>. |
unpublish_deck | Reverts to draft. The public URL stops resolving. |
delete_deck | Permanently deletes a deck and all its slides. |
get_brand | Fetches a single brand's full tokens. |
create_brand | Creates a new brand (clones tokens from active brand by default). |
update_brand | Patches a brand's colors, typography, logos, tone. |
set_active_brand | Marks a brand as the workspace default for new decks. |
delete_brand | Permanently deletes a brand. |
extract_brand_from_url | Visits a public URL, samples its colors/fonts/logos, and returns an ExtractedBrand payload. Costs 50 credits. |
generate_image | Generates one or more AI images from a prompt, saved to your workspace library and returned as URLs. Costs 80 credits per image. |
list_images | Lists every hosted image URL referenced across your workspace's decks. |
list_slide_templates_saved | Lists your workspace's saved (reusable) slide blocks. |
save_slide_template | Saves a slide's content as a reusable block. |
update_slide_template | Renames or updates a saved block. |
delete_slide_template | Deletes a saved block. |
apply_slide_template | Appends a saved block to a deck. |
list_deck_versions | Snapshot history for a deck — every save/publish/restore event. |
restore_deck_version | Rolls a deck back to a prior snapshot (current state is checkpointed first). |
create_slide_type | Creates a new custom slide type. |
update_slide_type | Updates a custom slide type's layout or defaults. |
delete_slide_type | Permanently deletes a custom slide type. |
send_test_email | Fires the invitation email template to a given address — for previewing email designs. |
#Example prompts
Try these with Claude after connecting:
"Create a deck about our Q3 product launch — include stats, a roadmap, and a CTA."
"List my slide templates, then create a deck called 'Q3 review' with a title, three stats, a process flow, and a CTA. Publish it when done."
"Open the deck
feature-tour, swap the testimonial for one from M. Müller, and republish."
"On the deck
feature-tour, change the cover title to 'Ship faster' and tighten the closing CTA to one line."
Claude calls list_slide_templates first to learn the schemas, designs the deck and writes the content itself, then create_deck + add_slides to build it and publish_deck to make it live. For targeted changes to an existing deck it reads it with get_deck and patches the affected slides with update_slide.
#Security
- Tokens are scoped to one user. Cross-workspace access is not possible.
- The endpoint is bearer-only — Clerk browser sessions are ignored on
/mcp. - All write tools enforce workspace ownership: a token can't edit a deck in another workspace even if it knows the deck id.
last_used_atis updated on every call so you can spot a leaked token in the dashboard.- Revoking a token via Account → MCP access sets
revoked_at; the next call returns 401.
#Notes
- A deck costs 100 credits, the same on every channel. Reading, manual edits, and PDF and PPTX exports are always free.
export_deckandpreview_deckhand you a short link (heydecks.com/s/<code>) straight from the client — no dashboard trip, no long token in the URL. The random code is the capability (like a presigned URL): it maps to exactly one deck + format, expires, and works while the deck is a draft.export_deckgives PDF on every plan, PPTX (Solo+) as native editable PowerPoint;preview_deckgives a PNG of a single slide and is free.generate_image(80 credits per image) andextract_brand_from_url(50 credits) cost more, since those call models on your behalf.add_slidesaccepts up to 60 slides per call. Build the whole deck in one shot, then publish.create_deckcan take the sameslidesarray to build in a single call.- A deck has two independent state fields.
status(draftvspublished) is whether the public URL resolves at all — change it withpublish_deck/unpublish_deck.visibility(public/password/expiring) is who may open it once it is live. So a new draft that reportsvisibility: publicis expected, not a conflict. - Set the deck language with
locale(enorde) oncreate_deck, or later withupdate_deck. It defaults to the brand's default locale, so passlocale: "de"up front for a German deck. - Image fields take a URL. The server doesn't upload binary images — pass an
https://URL (or generate one withgenerate_image) and the slide will fetch it at render time. - Slugs are unique per workspace. If a slug clashes, the server auto-suffixes (
-2,-3…).