tldraw-mcp
Minimal MCP server for editing tldraw .tldr files via JSON manipulation. Headless, no browser needed.
README
tldraw-mcp
Minimal MCP server for editing tldraw .tldr files via JSON manipulation. Headless, no browser needed.
Status
Working skeleton. Schema validation is wired (@tldraw/tlschema validators run before every write), fractional indexing uses @tldraw/utils, file writes are guarded by proper-lockfile. Output verified end-to-end against the real tldraw runtime via Store.loadStoreSnapshot() in the contract test layer.
Quick Start
Requires Node ≥ 20.
1. Install (user scope — available in every project):
claude mcp remove tldraw-m9810223 -s user 2>/dev/null; rm -rf ~/.npm/_npx
claude mcp add -s user tldraw-m9810223 -- npx -y github:m9810223/tldraw-mcp
Restart Claude Code. /mcp should now list tldraw-m9810223.
2. Try the demo prompt in Claude Code:
Draw the Shai-Hulud supply-chain attack flow described in this article with MCP `tldraw-m9810223`, save to `./demo.tldr`:
https://semgrep.dev/blog/2026/malicious-dependency-in-pytorch-lightning-used-for-ai-training/
- Match the actors and how data/control flows between them
- Polish the result at the end
3. View the result — drop ./demo.tldr onto tldraw.com, or use the tldraw VS Code extension for live preview.

Source file: docs/demo.tldr
Tools
File / page lifecycle
| Tool | What it does |
|---|---|
create_empty_file |
Create a fresh .tldr with a default page |
create_page |
Add a new page |
list_pages |
List pages with id, name, ordering index |
move_to_page |
Move shapes; bindings: 'error' | 'pull' | 'cut' controls binding handling |
Shapes
| Tool | What it does |
|---|---|
create_rect |
Create a rectangle (geo shape) |
create_text |
Create a text shape |
create_group |
Group shapes by reparenting them |
ungroup |
Dissolve a group, reparenting its children to the group's parent |
connect |
Arrow + bindings between two same-page shapes |
list_shapes |
List shapes — id, type, x, y, label only |
get_shape |
Full record of one shape by id |
update_shape |
Shallow-merge patch (use nested { "props": {...} } for prop edits) |
delete_shape |
Delete by id; cascade: true (default) also removes attached arrows + bindings |
Layout / text fitting
| Tool | What it does |
|---|---|
fit_to_text |
Resize a geo/text shape to fit its current text content |
align |
Align shapes on an axis (left/right/top/bottom/center-x/center-y) |
distribute |
Even-space shapes between the outermost two |
auto_layout |
Lay shapes out in a horizontal/vertical chain |
graph_layout |
Dagre layout for arrow-connected shapes (best for non-chain topologies) |
measure_arrow_labels |
Report label sizes + endpoint distances for labeled arrows |
bend_overlapping_arrows |
Bend parallel arrows (same shape pair) symmetrically; priority[] keeps important arrows straight. graph_layout calls this automatically. |
polish_layout |
One-shot finisher: fit_to_text every node + graph_layout (auto-bends arrows). Use as the last step after building a fresh diagram. |
Discovery & escape hatch
| Tool | What it does | Token cost |
|---|---|---|
search_api |
List supported shape types + curated required props. Pass {type, verbose:true} to dump live prop names from @tldraw/tlschema for any type (including ones not in the curated list) |
low / medium |
exec_jq |
Run a jq filter against the file. write=true persists (auto-checkpoint first) |
varies |
Checkpoints (safety)
| Tool | What it does | Token cost |
|---|---|---|
save_checkpoint |
Copy .tldr to a timestamped backup |
low |
list_checkpoints |
List backups, newest first | low |
restore_checkpoint |
Restore a backup (most recent if checkpoint omitted) |
low |
The token-saving design: tools take primitive args, return ids or ok. The full JSON only enters context when you call get_shape deliberately.
Install / Update / Remove
jq only needed for exec_jq (brew install jq / apt-get install jq).
# Install — user scope: every project on this machine (recommended)
claude mcp remove tldraw-m9810223 -s user 2>/dev/null; rm -rf ~/.npm/_npx
claude mcp add -s user tldraw-m9810223 -- npx -y github:m9810223/tldraw-mcp
# Install — local scope (default): only the current project directory
claude mcp remove tldraw-m9810223 2>/dev/null; rm -rf ~/.npm/_npx
claude mcp add tldraw-m9810223 -- npx -y github:m9810223/tldraw-mcp
The first arg (tldraw-m9810223) is the local server name — pick whatever you like, then refer to it the same way in subsequent commands. Restart Claude Code, then /mcp lists it with 26 tools.
Wire up to other MCP clients
Same JSON shape, different config file location:
| Client | Config path |
|---|---|
| Claude Desktop | ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) |
| Cursor | ~/.cursor/mcp.json |
| VS Code | .vscode/mcp.json |
Bootstrapping a .tldr file
Use the create_empty_file tool, or save an empty canvas from tldraw.com and point tools at the absolute path.
create_empty_file({ file: "/tmp/demo.tldr" })
Viewing / editing the output
| Tool | Notes |
|---|---|
| tldraw.com | Drag the .tldr file onto the page |
| tldraw VS Code extension | Native .tldr preview + edit inside VS Code; survives file changes from the MCP server |
| Tldraw Desktop / official editor | Drop the file in |
The VS Code extension is the smoothest dev loop — keep code path/to/file.tldr open in a tab while the MCP edits it; the editor refreshes on disk change.
Design comparison vs official tldraw-mcp-app
The Cloudflare-hosted official MCP exposes only search + exec (run any JS in a live tldraw Editor). This skeleton goes the opposite way — typed JSON edits over .tldr files — and borrows the discovery pattern (search_api) and escape hatch (exec_jq) so an LLM can fall through when typed tools don't cover an operation.
Official tldraw-mcp-app |
This skeleton | |
|---|---|---|
| Transport | streamable-http + sse (Cloudflare) | stdio (works in Claude Code directly) |
| Runtime | Real tldraw Editor in widget iframe | Pure Node, edits raw JSON |
| Tools | 2 (search, exec) + checkpoints |
26: file/page (4) + shape (9) + layout (8) + discovery (2) + ckpt (3) |
| Live preview | Yes (widget iframe) | No (open the file in tldraw to view) |
| Coverage | Whole Editor API | Geo / text / arrow + jq escape hatch |
Known gaps
index(z-order) only supports appending above the current max — no insert-between- No image / video / asset support
- Schema version pinning is informational only — opening a file in a newer tldraw may trigger migrations
search_apicurated list is hand-maintained alongside the live@tldraw/tlschemareflection
Architecture
src/
index.ts MCP server entry, tool registration (stdio transport)
tools.ts Tool handlers + zod input schemas
shapes.ts tldraw record factories (geo/text/arrow/group/binding)
store.ts Load/save .tldr + withFileLock; helpers (id gen, indexing, find, page-of-shape, bindings-for-shape)
template.ts Empty .tldr generator using @tldraw/tlschema serialize()
validate.ts validateShape / validateBinding using createShapeValidator + createBindingValidator
checkpoint.ts Timestamped backups under .tldraw-mcp-checkpoints/
jq.ts Shell-out to jq for the exec_jq escape hatch
text-metrics.ts Text size heuristics for autoFit + label measurement
graph-layout.ts Dagre wrapper for graph_layout
arrow-bending.ts Detect parallel-edge overlap + assign symmetric bend values
test/
unit/ store + validate + text-metrics + arrow-bending (34 tests)
integration/ tools end-to-end on tmp .tldr (39 tests)
contract/ loadStoreSnapshot against real @tldraw/store (4 tests)
boundary/ N-1 / N / N+1 limits + concurrent writes (89 tests)
Pure JSON manipulation — no @tldraw/store, no DOM, no React.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.