slide-mcp
Create designed Figma Slides from a prompt — using your own LLM API key (BYOK).
Type "Make an 8-slide product intro" in the plugin, and a polished, multi-layout deck appears in your open Figma Slides file — 39 layouts, 17 design systems, charts, images, tables, and more. Everything runs inside the plugin: no server, no account, and your API key never leaves your machine.
Contents
- How it works
- Install & build
- Load the plugin in Figma
- Use it (BYOK)
- Direct JSON (no LLM)
- IDE / MCP mode (optional)
- Choosing a design system
create_deckdata format- Layout reference
- Design systems
- Troubleshooting
- Updating the plugin
- Project structure
- Notes & limitations
How it works
The default mode is BYOK — a single Figma Slides plugin, no backend:
- You enter your API key and a topic in the plugin panel.
- The plugin calls your selected LLM (Anthropic, Google Gemini, or
OpenAI) with your key, asking it to design the deck and return it as create_deck JSON (structure, layouts, colors).
- The plugin's layout engine builds the slides in Figma.
You can also paste a create_deck JSON directly to build an exact deck without calling any LLM (see Direct JSON), or drive it from an IDE assistant via the bundled MCP server (see IDE / MCP mode) — useful when you'd rather use a Copilot/Claude subscription than per-token API billing.
The API key is stored locally via Figma's
clientStorage(this machine only) and is sent only to the provider you choose.
Install & build
The plugin loads from local files (manifest.json → code.js + ui.html), so build it once after cloning:
git clone https://github.com/Rikuto-des/slide-mcp.git
cd slide-mcp
npm install && npm run build # builds the plugin → code.js
code.jsandnode_modules/are git-ignored, so you build after cloning.
Load the plugin in Figma
- Open the Figma desktop app and open (or create) a Figma Slides file.
- Menu → Plugins → Development → Import plugin from manifest…
- Select
manifest.jsonfrom this repo. - Run it: Plugins → Development → slide-mcp.
You only import once. After code changes you just re-run it (a manifest.json change needs a re-import — see Updating).
Use it (BYOK)
In the plugin panel:
- Provider — choose Anthropic (Claude), Google Gemini, or OpenAI (GPT).
- API key — paste your own key (stored on this machine only; remembered per
provider). Get one:
- Anthropic → console.anthropic.com
- Gemini → aistudio.google.com
- OpenAI → platform.openai.com
- Model — pick or type a model id (suggestions per provider).
- (optional) Design system — pick one, or let the AI choose.
- Topic — describe the deck, then press 生成 / Generate.
Example topic:
自社プロダクトの紹介を8枚で。表紙、課題、解決策、主要機能3つ、実績の数値、料金、まとめ。
For very large decks (e.g. all 39 layouts) prefer a strong model — output can be long. See examples/ for ready-made prompts.
Direct JSON (no LLM)
Open "JSON直貼り" in the panel and paste a create_deck JSON ({ "slides": [ ... ] }) to build an exact deck with no API call — handy for reproducible decks or testing every layout. Example: examples/all-layouts.json renders all 39 layouts, one per slide.
IDE / MCP mode (optional — Copilot / use a subscription)
BYOK bills per token against your own API key. If you'd rather drive the plugin from an IDE assistant you already pay for (GitHub Copilot, or Claude Code/Desktop), use the bundled MCP server instead — the assistant calls the create_deck tool and the plugin builds the slides. The plugin itself never touches your subscription, so this stays within each tool's own terms.
Copilot / Claude ──stdio──▶ slide-mcp-server (MCP + WS bridge) ──WS──▶ this plugin
- Start the MCP server. The repo ships
.vscode/mcp.json, which runs the
published server via npx (npx -y slide-mcp-server@latest). In VS Code, start the slide-mcp server from the MCP list (Copilot Agent mode).
- In the plugin panel, open "IDE / MCP 連携" and press 接続. It connects
to ws://localhost:3055 and flips to 接続済み.
- Ask the assistant: "slide-mcp で〜のデッキを作って".
Running in GitHub Codespaces (private tunnel, browser-only OK)
Figma runs on your local machine, so the plugin must reach the bridge inside the Codespace. Use GitHub's authenticated, private port forward — no public exposure:
- In the Codespace, the server binds
0.0.0.0(set in.vscode/mcp.jsonvia
SLIDE_MCP_HOST=0.0.0.0). Start it from the Copilot MCP list.
- On your local machine, forward the port (works even if the Codespace is
browser-only):
gh codespace ports forward 3055:3055 -c <codespace-name>
# optional one-word alias in ~/.zshrc:
# alias slidetunnel='gh codespace ports forward 3055:3055 -c <codespace-name>'
The port stays Private (GitHub-authenticated) — it is not made public.
- The plugin's
ws://localhost:3055now tunnels to the Codespace. Press 接続.
Run the server in one place only. Don't also start a local
slide-mcp-serverwhile the tunnel is up — two servers fighting for port 3055 is the usual cause of "connected but nothing happens".
Choosing a design system
You can set the look in three places (most specific wins):
- In the plugin panel — the panel lists all 17 systems with color swatches.
Click one; it becomes the default whenever a deck doesn't specify a theme. Your choice is remembered across sessions.
- Per deck — set
theme.preset(e.g."theme": { "preset": "ocean" }). - Per slide — set
slide.theme.preseton a single slide (e.g. one dark
section inside a light deck).
create_deck data format
This is the JSON the LLM produces — and what you can paste into JSON直貼り:
{
"replace": true, // optional: delete existing slides first
"theme": { // optional; omit to use the panel default
"preset": "light", // one of the 17 systems (see below)
"accent": "#2563eb", // optional per-field color overrides:
"background": "#ffffff",
"titleColor": "#0f172a",
"bodyColor": "#334155",
"secondaryColor": "#64748b",
"surfaceColor": "#f1f5f9",
"font": "Inter", // preferred font family (best-effort)
"pageNumbers": true // footer page numbers (default true)
},
"slides": [
{
"layout": "content", // optional; auto-detected if omitted
"kicker": "string", // small eyebrow label above the title
"title": "string",
"subtitle": "string",
"body": "string", // paragraph; for statement/quote/code it's the message/code
"bullets": ["string", "..."],
"items": [ // structured rows (charts, cards, steps, …)
{ "title": "", "value": "", "label": "", "desc": "", "bullets": ["..."], "image": "https://…" }
],
"image": "https://…", // for image-right/left, hero, gallery, team
"table": { "headers": ["A","B"], "rows": [["1","2"],["3","4"]] },
"notes": "string", // speaker notes (stored as plugin data)
"background": "#0B1021", // per-slide background (hex or a name)
"theme": { "preset": "dark" } // per-slide design-system override
}
]
}
Layout reference
Omit layout to auto-detect: a title-only slide becomes cover (first slide) or section; anything with body/bullets/items becomes content.
| layout | shows | main fields | | --- | --- | --- | | cover | title slide with a side color panel | kicker, title, subtitle | | cover-bold | full-bleed accent bg, centered title | kicker, title, subtitle | | cover-minimal | editorial whitespace, left-aligned + rule | kicker, title, subtitle | | cover-split | 50/50 accent panel + title | kicker, title, subtitle | | section | divider with a big ghost number | kicker, title, subtitle | | closing | closing / thank-you slide | kicker, title, subtitle | | content | title + numbered bullets | kicker, title, subtitle, body, bullets[] | | two-col | bullets in two columns | kicker, title, bullets[] | | checklist | ✓ checklist | kicker, title, bullets[] | | agenda | numbered table of contents | title, bullets[] | | split | term / definition rows | title, items[].title + items[].desc | | quadrant | 2×2 matrix of four cards | title, items[].title/desc (4) | | statement | one big quote / takeaway | body, subtitle | | quote | designed pull-quote + author | body, subtitle | | callout | highlighted message box | body, subtitle | | stats | 2–4 big numbers | title, items[].value/label/desc | | big-number | one huge KPI | kicker, items[0].value/label/desc | | gauge | single circular % gauge + label | title, items[0].value/label/desc | | bars | horizontal bar chart | title, items[].label/value | | columns | vertical column chart | title, items[].label/value | | progress | percent progress bars | title, items[].label/value (0–100) | | donut | donut / pie chart + legend | title, items[].label/value | | line | line chart | title, items[].label/value | | funnel | funnel | title, items[].label/value | | pyramid | hierarchy pyramid | title, items[].label (+value) | | steps | numbered process row | title, items[].title/desc | | roadmap | horizontal phased roadmap | title, items[].title/desc (3–5) | | timeline | vertical timeline | title, items[].title/desc | | compare | two cards side by side | title, items[0..1].title + bullets[] | | cards | 2–4 feature cards | title, items[].title/desc | | table | data table (zebra rows) | title, table.headers[], table.rows[][] | | split-mix | text left + image/chart right | title, bullets/body + image OR items[] | | team | profile cards with avatars | title, items[].image/title/desc | | testimonial | quote + avatar + name/role | body, image, subtitle, items[0].desc | | image-right | text left, image right | kicker, title, bullets[], image | | image-left | image left, text right | kicker, title, body, image | | hero | full-bleed image + overlaid title | kicker, title, subtitle, image | | gallery | grid of images with captions | title, items[].image/title | | code | code on a dark panel (monospace) | title, body (the code; newlines kept) |
Notes:
- Charts (
bars,columns,progress,donut,line,funnel,pyramid,
gauge) read a number out of items[].value (e.g. "68%", "1,200").
- Covers:
cover(side panel),cover-bold(full accent, centered),
cover-minimal (editorial), cover-split (50/50).
- Images accept any
httpsPNG / JPEG / GIF URL (max 4096 px). A bad/slow URL
falls back to a plain placeholder after ~7 s.
Design systems (theme.preset)
17 systems, each a 6-color palette (some with a preferred font):
- Light:
light(default),sky,ocean,emerald,forest,warm,
sunset, rose, plum, indigo, mono, paper (serif)
- Dark:
dark,midnight,graphite,carbon,royal
See Choosing a design system for how to select one.
Troubleshooting
- "APIエラー" / API error. Check the API key, the model id, and that the key
has credit. The exact provider message is shown in the panel.
- "呼び出しに失敗 (CORS / Failed to fetch)". A provider's API blocked the
direct browser request. Anthropic supports direct calls; if Gemini or OpenAI is blocked in your environment, switch providers or open an issue.
- "生成結果の解析に失敗". The model's output wasn't valid JSON — usually it was
cut off because the deck was too long. Ask for fewer slides or use a stronger model (Opus / Sonnet / GPT‑4o / Gemini Pro).
- Images show as gray boxes. The image URL was unreachable/blocked or timed
out (~7 s).
- Japanese text looks wrong / boxes. Install/keep Noto Sans JP in Figma
(the plugin auto-prefers it for CJK and falls back to Inter). Override with theme.font.
Updating the plugin
- Changed
code.tsorui.html?npm run build, then re-run the plugin
in Figma (Plugins → Development → slide-mcp). Re-running reloads code.js + ui.html from disk.
- Changed
manifest.json? Re-import the plugin (Plugins → Development →
Import plugin from manifest…). A re-run is not enough for manifest changes.
Project structure
manifest.json Figma plugin manifest (entry: code.js, ui: ui.html)
code.ts Plugin main thread — layout engine (build → code.js)
ui.html Plugin UI — BYOK panel + JSON-paste + IDE/MCP connect
tsconfig.json Plugin TS config (target es2017 — required by Figma)
.vscode/mcp.json VS Code MCP server config (for the IDE/MCP path)
server/ MCP server + WebSocket bridge (optional — IDE/MCP mode)
src/index.ts MCP server (stdio) + WS bridge; generate.mjs CLI
examples/ Ready-made prompts + create_deck JSON (incl. all-layouts.json)
assets/community/ Figma Community publishing assets
Notes & limitations
- BYOK / privacy: your API key is stored locally (
clientStorage) and sent
only to the provider you pick. The plugin has no backend and collects nothing.
- Network access:
manifest.jsonallows*so the plugin can reach the three
provider APIs and fetch user-supplied image URLs (any host).
- Speaker notes: Figma's plugin API has no native speaker-notes field, so
notes are stored on the slide via setSharedPluginData("slide_mcp", "notes").
- TypeScript target: the plugin builds to es2017 — Figma's plugin runtime
rejects newer syntax. Don't raise the target.
- Disclaimer: an unofficial, community project — not affiliated with, sponsored
by, or endorsed by Figma or Anthropic. "Figma" is a trademark of Figma, Inc., used here only descriptively to say what this tool works with.
Develop
npm run watch # rebuild code.ts → code.js on save
After changing the plugin, re-run it from Figma's Plugins → Development menu.











