Figma Remote MCP integration for OpenClaw. Reads designs via figma__* tools; creates and edits via CC sessions using mcp__figma__* tools.
Read/Inspect → call figma__* tools directly. No CC session needed.
Write/Create/Edit → requires CC session via mcp__figma__* tools.
Seeing or understanding a design? → Direct. Do not start a session.
Changing or creating something? → Start a CC session. Follow the matching playbook below.
Execution model:
First: Determine the user's intent, then follow the matching path.
This is an abridged routing summary. For the full matrix and decision logic, see references/workflow-selection.md.
→ Full routing matrix: references/workflow-selection.md
IntentPathRouteBuild a production screenNative Screen GenerationCCCreate next step / state variant from an existing screenNative Screen GenerationCCPrototype from HTML/URLHTML-to-Figma PrototypingCCRead-only inspectionget_design_context / get_screenshotDirectReview + Edit a screenScreen Review LoopCCApply design tokensColor TokenizationCCImport + clean up Stitch exportStitch Import CleanupCCDiscover variables/stylesVariable DiscoveryDirectAudit design systemDesign System CleanupCCInspect finished designDesign Audit ReviewDirect
Screenshots must reach the user as Telegram photo attachments — not as inline base64 text.
Workflow:
Save to file — use --out <path> flag so the PNG is written directly:
bash
node scripts/figma-mcp-cli.mjs get_screenshot \
fileKey=<fileKey> nodeId=<nodeId> scale=2 \
--out ~/workspace-dev-botti/screenshots/<name>.png
Deliver to user — put MEDIA:<path> on its own line in your reply:
text
Hier ist der aktuelle Stand:
MEDIA:screenshots/validate.png
OpenClaw extracts every MEDIA: line and sends the file as a native Telegram photo.
The path is workspace-relative ( screenshots/...) or absolute.
Two different tools — don't mix them up:
ToolPurposeUsed for Image Delivery?image toolSend to Vision model for analysis❌ No — analysis onlyMEDIA:<path> in reply textSend as Telegram attachment✅ Yes — actual delivery
Why --out?
Without it, the Figma API returns base64-encoded JSON → renders as inline text in Telegram, not a photo. The --out flag decodes and writes a real PNG file that MEDIA: sends as an attachment.
Screenshot directory: ~/workspace-dev-botti/screenshots/ (create if missing)
Validation pattern (every write operation):
bash
# After use_figma call — save screenshot → MEDIA: in reply
node scripts/figma-mcp-cli.mjs get_screenshot fileKey=<key> nodeId=<id> scale=2 \
--out ~/workspace-dev-botti/screenshots/validate.png
# Reply with:
# MEDIA:screenshots/validate.png
Stitch comparison:
Stitch delivers via MEDIA:<screenshotUrl> (HTTP URL). Figma delivers via MEDIA:<local-path> (file). Mechanism identical — only the source differs.
These are non-negotiable. Full rule set: references/core-rules.md
get_screenshot or get_metadata after each use_figma call. Never assume success.use_figma call, validate between sections.Before writing any use_figma code, know these failure modes:
→ Full reference: references/plugin-api-gotchas.md
setBoundVariableForPaint returns a new paint — reassign the fills/strokes array ( #paint-binding)figma.currentPage may reset between calls ( #page-context)layoutSizingHorizontal: "FILL" ( #append-before-fill)await async operations — loadFontAsync, importComponentByKeyAsync, etc. ( #promises)→ Full patterns: references/prompting-patterns.md
Key patterns: variable-first code structure, section-by-section execution, explicit design-system usage, validation loops, error recovery framing.
If dependencies are missing, install them from the skill repo root:
bash
npm install
Then run one-time bootstrap:
bash
node ~/.openclaw/skills/figma-agent/scripts/auth.mjs
Reads CC OAuth token from ~/.claude/.credentials.json, writes it into ~/.openclaw/openclaw.json. Then restart the OpenClaw gateway.
Token check: node ~/.openclaw/skills/figma-agent/scripts/auth.mjs --check
On 401 errors: Open CC → use any Figma tool (auto-refreshes token) → re-run bootstrap script.
text
figma.com/design/:fileKey/:name?node-id=:nodeId
Convert - to : in nodeId (e.g. 123-456 → 123:456). For FigJam: figma.com/board/:fileKey/:name → use get_figjam.