excalidraw-mcp
Build Excalidraw diagrams through the official Excalidraw MCP and turn the same source into a real .excalidraw file on disk or an Obsidian .excalidraw.md drawing. Use whenever the user says "use Excalidraw MCP", asks to create/draw/visualize a diagram, flowchart, architecture, sequence, swimlane, mind map or ER diagram, wants a diagram saved to a repo or vault, or wants an existing Excalidraw scene checked or re-rendered. Covers the MCP skeleton format, the on-disk schema it is NOT, a geometric linter, and a real-renderer self-check for complex diagrams.
- License 许可
- MIT
- 最近更新
- 2026-11-13
- Stars
- ★ 47
- Forks
- 5
01 前言 Front Matter
- name
- excalidraw-mcp
- license
- MIT
- version
- 1.2.0
- mcp-deps
- [ "excalidraw" ]
- repository
- anton-abyzov/vskill
- description
- Build Excalidraw diagrams through the official Excalidraw MCP and turn the same source into a real .excalidraw file on disk or an Obsidian .excalidraw.md drawing. Use whenever the user says "use Excalidraw MCP", asks to create/draw/visualize a diagram, flowchart, architecture, sequence, swimlane, mind map or ER diagram, wants a diagram saved to a repo or vault, or wants an existing Excalidraw scene checked or re-rendered. Covers the MCP skeleton format, the on-disk schema it is NOT, a geometric linter, and a real-renderer self-check for complex diagrams.
- allowed-tools
- Bash, Read, Write, Edit, mcp__excalidraw__read_me, mcp__excalidraw__create_view, mcp__excalidraw__export_to_excalidraw, mcp__excalidraw__save_checkpoint, mcp__excalidraw__read_checkpoint
02 资源文件 13
- 其他.gitignore29 B
- 其他examples/specweave-lifecycle.excalidraw28.1 KB
- 参考文档examples/specweave-lifecycle.excalidraw.md20.3 KB
- 参考文档examples/specweave-lifecycle.skeleton.json3.2 KB
- 参考文档references/file-format.md4.6 KB
- 参考文档references/layout-recipes.md4.2 KB
- 参考文档references/mcp-workflow.md3.9 KB
- 参考文档references/obsidian.md2.2 KB
- 脚本scripts/ensure_mcp.py6.4 KB
- 脚本scripts/excalidraw_build.py21.0 KB
- 脚本scripts/excalidraw_lint.py14.3 KB
- 脚本scripts/excalidraw_render.py4.2 KB
- 脚本scripts/split_excalidraw_library.py5.4 KB
03 SKILL.md 正文
Excalidraw via MCP
Saying "use Excalidraw MCP" should be enough to get a complicated diagram, drawn live and saved where it belongs. This skill is what makes that true.
The one thing that breaks everything
create_view's element format is a skeleton, not the on-disk schema. A shape's
label is skeleton-only sugar. Excalidraw's canvas renderer has no text branch for
rectangle / ellipse / diamond — container text is drawn only via
boundElements → containerId. So pasting create_view JSON into a .excalidraw file
produces empty boxes, silently. That single fact is why scripts/excalidraw_build.py
exists: author once in the skeleton, get both the live render and a correct file.
Second fact: hand-authored diagrams do not degrade gradually with size — they fail on irregularity. Measured on a real generated scene, elements produced by a repeating layout formula had a 0.00 defect rate; bespoke one-off elements had 0.71. So compute positions with a formula, and let the linter check the result.
Preflight on a new machine
Installing this skill does not install the MCP server — mcp-deps is a declaration
that vskill check verifies, not an installer. If the mcp__excalidraw__* tools are
not available, run this first — it detects and registers the server, on any OS:
python3 scripts/ensure_mcp.py --install
It reports where the server was found, or runs
claude mcp add --transport http --scope user excalidraw https://mcp.excalidraw.com
and re-verifies. Exit 0 configured, 1 missing, 2 could not register (no Claude CLI on
PATH — it prints the command to run by hand). Claude Code needs a restart afterwards to
pick up a newly added server.
Scopes: --scope user (default) covers every project on the machine via ~/.claude.json;
--scope project writes ./.mcp.json so teammates get it on clone; --scope local is
this project only. A server registered under a different project counts as missing —
Claude Code will not load it here, and the script says so.
Without the MCP everything except the live inline render still works.
excalidraw_build.py and excalidraw_lint.py are stdlib-only Python 3 — no packages, no
network. Build files, lint them, ship them. excalidraw_render.py additionally needs
pip install playwright && playwright install chromium.
Windows
Use py -3 and backslashes; python3 on Windows is a Microsoft Store stub that opens
the Store instead of running anything.
py -3 scripts\ensure_mcp.py --install
py -3 scripts\excalidraw_build.py scene.json -o out.excalidraw
Everything else is portable: paths go through pathlib, output is written with explicit
UTF-8 and \n newlines so a Windows run does not bake CRLF into the scene JSON, and the
preflight resolves claude.cmd / claude.exe as well as claude. If vskill i warns
that symlinks are unavailable, it falls back to copying — enable Developer Mode to get
symlinks back.
Workflow
- Preflight (new machine only): if the
mcp__excalidraw__*tools are missing,python3 scripts/ensure_mcp.py --install(py -3on Windows). - Author the skeleton. One JSON array, the same one
create_viewtakes. Positions come from a layout formula (seereferences/layout-recipes.md), never from eyeballing. - Lint it — offline, no dependencies, catches overflow/collision/geometry:
python3 scripts/excalidraw_lint.py scene.json --camera--cameraprints a correctly framed 4:3cameraUpdateto paste at the top. - Render it live with
mcp__excalidraw__create_view, elements streamed in z-order with camera moves (seereferences/mcp-workflow.md). Keep the returnedcheckpointId. - Save the file when the user wants one on disk:
python3 scripts/excalidraw_build.py scene.json -o out.excalidraw python3 scripts/excalidraw_build.py scene.json -o out --obsidian # → out.excalidraw.md python3 scripts/excalidraw_build.py scene.json -o out.excalidraw --dark - Look at it before declaring success on anything non-trivial. This renders through
Excalidraw's own
exportToSvg, so text is measured with real font metrics:
Then Read the PNG. Fix what you see; re-lint; re-render.python3 scripts/excalidraw_render.py out.excalidraw -o /tmp/preview.png
Steps 2 and 5 are the quality gate. Skipping them is how labels end up outside their boxes and arrows end up pointing at nothing.
Skeleton cheat sheet
{"type":"rectangle","id":"api","x":100,"y":80,"width":180,"height":80,
"roundness":{"type":3},"backgroundColor":"#a5d8ff","fillStyle":"solid",
"strokeColor":"#4a9eed","label":{"text":"API Gateway","fontSize":18}}
{"type":"arrow","id":"e1","from":"api","to":"db","label":{"text":"SQL"}} // auto-bound
{"type":"arrow","id":"e2","from":"api","to":"db","route":"ortho"} // L-shaped
{"type":"arrow","id":"e3","x":300,"y":150,"points":[[0,0],[120,0]]} // manual
{"type":"text","id":"ttl","center":400,"y":20,"text":"Title","fontSize":24} // auto-centred
{"type":"rectangle","id":"zone","x":40,"y":40,"width":700,"height":420,
"opacity":30,"zoneLabel":"Data layer"} // caption, not bound label
Builder-only extensions: from/to (perimeter anchors + two-way binding),
route:"ortho", zoneLabel, center on text, fixedWidth on a shape (wrap instead
of grow). Everything else is passed through unchanged, so the same array still works
verbatim with create_view.
Never put a bound label on a background zone rectangle — it centres in the middle
of the zone and cannot be grabbed. Use zoneLabel.
Choosing the output
| Destination | Command | Notes |
|---|---|---|
| Show the user now | create_view |
animated, camera-guided; returns checkpointId |
| File in a repo | excalidraw_build.py -o x.excalidraw |
opens at excalidraw.com or in the VS Code extension |
| Obsidian vault | ... -o x --obsidian |
.excalidraw.md, plugin-parsed, git-diffable |
| Shareable link | mcp__excalidraw__export_to_excalidraw |
uploads to excalidraw.com — ask first |
The MCP has no local-file tool. export_to_excalidraw is a public upload, so treat it
as publishing: confirm with the user before calling it.
Iterating
create_view returns a checkpointId. To continue from it — including user edits made
in fullscreen — start the next array with
{"type":"restoreCheckpoint","id":"<checkpointId>"} and append only what is new. Use
{"type":"delete","ids":"a,b"} to remove elements; never reuse a deleted id. Keep the
skeleton file on disk in sync, since that file is what builds and lints.
References
references/file-format.md— the on-disk schema, verified against upstream: font codes, bound text, arrow geometry, bindings, what Excalidraw does and does not recompute on open. Read before hand-editing any.excalidrawfile.references/mcp-workflow.md— camera choreography, streaming order, checkpoints, dark mode, and the MCP's own limits.references/layout-recipes.md— formulas for flow, layered, swimlane, sequence, grid, radial and matrix layouts, plus how to keep a 60-element diagram legible.references/obsidian.md— the.excalidraw.mdwrapper, block-ref rules, and the compressed-scene gotcha.scripts/ensure_mcp.py— detect and register the Excalidraw MCP server on any OS.scripts/split_excalidraw_library.py— split an.excalidrawlib(AWS/GCP/K8s icon packs from libraries.excalidraw.com) into per-icon JSON plus a lookup table, so icon data never enters context.
Limits worth stating out loud
- Width estimates are calibrated per-character, not measured from the font binary; the linter warns inside 10% of overflow. When it warns on something important, render it.
excalidraw_render.pyneedsplaywrightplus network access to esm.sh. Without them, lint is still fully offline.- The linter cannot judge whether a diagram is good, only whether it is correct. Composition is still your job.
Changelog
- 1.2.0 —
scripts/ensure_mcp.py: cross-platform preflight that detects the MCP server (including~/.claude.json's per-project map) and registers it when missing. Windows support: documentedpy -3,claude.cmdresolution, explicit UTF-8 and\nnewlines on every write. - 1.1.1 — linter no longer applies the box-fit rules (R1/R2) to arrow containers; arrow labels are laid along the path and are covered by R10.
- 1.1.0 — moved into the vskill monorepo at
skills/excalidraw-mcp/, matchingremotion-best-practicesand the other in-repo skills. The standaloneanton-abyzov/excalidraw-mcp-skillrepo is deprecated. - 1.0.1 — document MCP setup: installing the skill does not install the server;
added the
claude mcp addone-liner and what still works without it. - 1.0.0 — first release. Replaces the file-only
excalidraw-diagram-generatorskill, whose templates emitted inlinetexton shapes and therefore opened as empty boxes.
04 同仓库更多 Skills
x-reply-drafts
Find live X threads where a product genuinely fits, and draft truthful, humanized replies for the owner to review and post by hand. Human pace only: max 5 replies a day, never two within 20 minutes, no automated posting. Use when the user asks to 'find threads to reply to', 'draft X replies', 'reply-guy session', 'join trending conversations', 'engage on Twitter about <product>', or wants a daily batch of reply drafts. Not for scheduling original posts (social-media-posting) or bulk publishing (blotato).
hello-world
A tiny test skill used by the 0853 verify-runtime harness. Says hello. No external calls. Use when the user asks for a sanity-check skill in a verify-harness fixture.
existing-skill
Lint markdown files for style and grammar issues.
remotion-best-practices
Best practices for Remotion video creation in React — scaffolding, compositions, animations, transitions — PLUS hard-won rules for high-fidelity product-demo videos: real logos/icons, precise YouTube-reference matching, full-screen camera zooms, click-targets that actually hit, content-tight rectangle highlights, voiceover regeneration discipline, audio-level normalization (no double-boost), per-scene voice-sync math, Studio detail-page mirror patterns, bold-not-subtle connection lines, and the YouTube publication kit (chapters, description, thumbnail, hashtags) that turns a render into a shipped video.
rea
Find out exactly how a feature is implemented in a shipped tool or app you don't have the source for (desktop apps, Electron apps like Claude desktop, native CLIs like Codex, websites, APKs, .NET assemblies) using REA - Reverse Engineer Anything (github.com/morluto/rea). Sets REA up when it is missing (CLI, MCP registration, Hopper or Ghidra), routes the target to the right REA tool, keeps evidence out of the context window, and turns findings into a clean-room spec before any rebuild. Use when the user says 'use REA', 'reverse engineer', 'how does <app> do X', 'how is this feature implemented in <tool>', 'clone this feature', 'decompile', 'look inside the app', or asks how a closed-source competitor works. Skip it when the source is available - read the repo instead.
motion-graphics-promo
After Effects-style motion graphics for short product promos (15-45 s, vertical or landscape), built as code with HyperFrames + GSAP. Covers a story-first brief, motion grammar (energetic entry, one transition per task, spring settle, 2-3 s of stable proof), a 32-second promo timeline, device-frame and kinetic-type recipes, vertical-first composition, evidence rules (real UI only, no fake clicks), music licensing and encoded-frame verification. Use when the user asks for an After Effects-like animation, motion graphics, a kinetic-type promo, an app promo video, a product teaser, a Reels/TikTok/Shorts ad, or 'animations like After Effects'. Also covers short explainers, tutorials and 15-second vertical ads: a design kit (footage beds, condensed caps in a marker box, white device frames, falling stickers, voice-over with music ducking) and HyperFrames render traps that silently break output. Pairs with hyperframes-best-practices (screencast pipeline) and remotion-best-practices.