Excalidraw MCP Diagram Agent
Allows generating editable Excalidraw diagrams from textual descriptions, with proper shape bindings, arrow connections, and non-overlapping layout, as well as validating existing Excalidraw scenes.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Excalidraw MCP Diagram AgentCreate a diagram for: mobile app calls API gateway, which queries Postgres and Redis."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Excalidraw MCP Diagram Agent
An MCP server that turns a sentence about a system into a real, editable Excalidraw file.
Not a picture of a diagram — a .excalidraw document you can open at excalidraw.com, drag a box in, and watch the arrows follow. Arrows are genuinely bound to the shapes they connect, labels are genuinely bound to their containers, and shapes never overlap.

That picture was generated from this, with no model involved:
A React storefront calls the API gateway. The API gateway authenticates with Auth0
and forwards requests to the orders service. The orders service queries the Postgres
database, caches in Redis and publishes to Kafka. A billing worker consumes from
Kafka, calls Stripe and writes to the Postgres database.The scene it produced is in docs/example-checkout.excalidraw — open it and move something.
The thing that is actually hard
Emitting JSON that Excalidraw accepts is easy. Excalidraw's restore() runs on every import and quietly patches whatever you left out, so a half-correct file still opens and looks fine. You find out it was wrong later, when someone drags a box and every arrow stays behind.
Three failures hide behind a valid-looking file:
One-sided bindings. An arrow names its shapes in
startBinding/endBinding, but the shapes must name the arrow back inboundElements. Miss the back-reference and the file opens perfectly and stops behaving like a diagram the moment you move anything.Floating arrows. Excalidraw decides an arrow is bound from the binding records, but it draws the shaft from the element's own
points. Both have to agree, and the points have to land on the real outline of the shape — which is a different equation for a rectangle, an ellipse and a diamond.Boxes on top of boxes. Schema-valid JSON that renders as an unreadable pile is still a failed diagram.
So the validator here checks three separate things, and only the third catches the failure that matters most: bindings that are perfect on paper attached to arrows that visibly float.
Related MCP server: Excalidraw MCP Server
How it works
description ──► graph (nodes + edges) ──► layout ──► scene ──► validate
▲ ▲
rule parser language modelEverything upstream of the graph is interchangeable; everything downstream is deterministic Python. The model — when there is one — never sees Excalidraw's schema and never produces a coordinate. It emits a tiny JSON graph and nothing else. That split is the whole design: the part that must be exactly right is kept out of the hands of the part that is only usually right, and a model failure degrades to the rule parser instead of to a broken file.
The layout is a small Sugiyama-style layered pass: break cycles, assign layers by longest path, insert dummy nodes so a long edge reserves a corridor instead of ploughing through the boxes between its ends, order within layers by barycentre sweeps to cut crossings, then assign coordinates. Non-overlap is structural rather than checked afterwards — layers occupy disjoint bands and siblings are stacked with a fixed gap — and the validator asserts it anyway.
Install
Python 3.10+.
git clone https://github.com/dev48v/excalidraw-mcp-agent
cd excalidraw-mcp-agent
python -m venv .venv && . .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"Quickstart
The CLI runs the same pipeline the MCP server does:
excalidraw-diagram --offline -t "Checkout" -o checkout.excalidraw \
"A React storefront calls the API gateway, which queries Postgres and publishes to Kafka."[rules] 4 nodes, 3 edges, 15 elements, 6 bindings -> checkout.excalidrawOpen checkout.excalidraw at excalidraw.com. Useful flags:
Flag | Effect |
| never call a model; rule parser only, fully deterministic |
| fail rather than silently downgrading to the rule parser |
| flow top-to-bottom instead of left-to-right |
| read the description from a pipe |
Arrow syntax works too, and mixes freely with prose:
excalidraw-diagram --offline "Browser -> CDN -> Load Balancer -> App Server: HTTPS"Optional: the model backend
The rule parser is a first-class path, not a fallback — the renderer cannot tell which front end produced the graph it is drawing. But a model handles phrasing the verb table does not.
cp .env.example .env
# NVIDIA_API_KEY=nvapi-... free tier at https://build.nvidia.comAny OpenAI-compatible endpoint works — Ollama, vLLM, OpenRouter — via EXCALIDRAW_MCP_BASE_URL and EXCALIDRAW_MCP_MODEL. With no key set, everything still runs; it just uses the rules.
Wire it into an MCP client
The server speaks stdio.
Claude Code
claude mcp add excalidraw -- /abs/path/to/.venv/bin/excalidraw-mcp-agentClaude Desktop — add to claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/, Windows: %APPDATA%\Claude\):
{
"mcpServers": {
"excalidraw": {
"command": "/abs/path/to/.venv/bin/excalidraw-mcp-agent",
"env": { "NVIDIA_API_KEY": "" }
}
}
}On Windows the command is C:\\path\\to\\.venv\\Scripts\\excalidraw-mcp-agent.exe. Use an absolute path: MCP clients do not inherit your shell's PATH.
Then ask for a diagram in plain English:
Draw me the checkout flow: a React storefront calls the API gateway, which authenticates with Auth0 and forwards to the orders service; the orders service queries Postgres, caches in Redis and publishes to Kafka. Save it to ~/checkout.excalidraw
Tools
Tool | Does |
| description → complete scene. Optional |
| checks a scene you already have — JSON string or a path — for schema errors, one-sided bindings, floating arrows and overlaps. |
| says whether a model is configured or the run will be offline, so a downgrade is distinguishable from a deliberate offline run. |
create_diagram returns the scene and a summary, so the client can see what it got:
{
"title": "Order Checkout Flow",
"backend": "rules",
"nodes": 9, "edges": 9,
"elements": 37, "shapes": 9, "arrows": 9, "labels": 19,
"bindings": 18,
"valid": true, "errors": [], "warnings": [], "notes": []
}Nine arrows, eighteen bindings — every arrow attached at both ends.
Node kinds
The kind decides the shape and the colour, and is inferred from the label when no model supplies one.
Kind | Shape | Inferred from |
| violet rectangle | browser, frontend, mobile, SPA, dashboard |
| blue rectangle | api, server, worker, lambda, gateway (the default) |
| green ellipse | postgres, mysql, mongo, dynamo, rds |
| green rectangle | redis, cache, s3, bucket, elasticsearch |
| dashed orange rectangle | kafka, sqs, topic, stream, pubsub |
| dashed grey rectangle | stripe, twilio, third-party, webhook |
| orange diamond | router, switch, branch, condition |
Verifying it for yourself
pytest covers the graph, the parser, the layout, the geometry, the scene builder and the validator:
pytest
# 114 passedThose are Python assertions about Python objects, which is exactly the trap this project is about — so there is a second harness that renders the output with Excalidraw's own engine. It needs Node and Chrome and a 14 MB bundle, so it is not part of the package or the test suite:
cd tools/render
npm install
npx esbuild entry.mjs --bundle --outfile=bundle.js --format=iife \
--define:process.env.NODE_ENV=\"production\" --loader:.woff2=dataurl
cd ../..
python tools/render/verify.py docs/example-checkout.excalidraw[PASS] example-checkout.excalidraw
svg : 2260 x 953.7184460878227
drawn nodes: 129 (20 text)
restore() : 0 element(s) changed
screenshot : tools/render/out/example-checkout.pngIt does two things a schema check cannot. It draws the scene with the real exportToSvg, so a malformed element shows up as a broken or empty picture rather than a passing assertion. And it runs the file through Excalidraw's own restore() and diffs the result against what we generated — restore() being the function that silently repairs imported files. Zero elements changed means the file needed no repair at all.
It also writes a PNG, cropped to the drawing, which is the only way to catch the failure no assertion describes: a diagram that is correct and unreadable.
Honest limits
The rule parser is a verb table, not language understanding. It knows about fifty verb phrases and the
A -> Bform. Sentences it cannot parse are dropped rather than guessed at, so odd phrasing costs you an edge, never a wrong diagram — but it does cost you the edge.The model summarises. Asked to draw a worker that "fetches the file from S3 and writes a thumbnail back to S3", an 8B model returned one edge, not two.
--require-modelgets you the model's reading of your description, not a transcription of it.Crossings are reduced, not eliminated. Barycentre ordering is a heuristic. On the example above,
billing worker → Kafkastill crossesorders service → Postgres. Non-overlap of boxes is guaranteed; non-crossing of arrows is not, and cannot be in general.Text is measured by estimate. Excalidraw measures with real font metrics in a browser; this has neither the fonts nor a canvas, so widths are a deliberate slight over-estimate. Boxes are a few pixels wider than they need to be, which beats a box that clips its own label.
Arrow labels may overhang their arrows. Given the choice between a label wider than its edge and hard-splitting
authenticatesintoauthenticate+s with, this picks the overhang.Self-loops are dropped. An edge from a node to itself needs routing this layout does not do, so it is skipped rather than drawn as junk.
Layered layout suits pipelines and architectures. A dense mesh with no clear direction will lay out legally and read poorly.
Two directions, seven kinds, one style. No groups, frames, images, freedraw or nested containers. Node labels are capped at five words.
The MCP server is built against
mcp2.x, where the ergonomic class ismcp.server.mcpserver.MCPServerandFastMCPis gone. Most tutorials you will find describe the 1.x API.
Licence
MIT © Devanshu Biswas. See LICENSE.
Project #1 of the Weekend Builds series.
Available Tools
3 toolscreate_diagramCreate an Excalidraw diagramA
Describe a system in plain English and get back a complete, editable Excalidraw scene: shapes laid out automatically, arrows genuinely bound to the shapes they connect, and labels attached to their containers. Optionally writes the scene to a .excalidraw file.
| Name | Required | Description | Default |
|---|---|---|---|
| title | No | Optional title drawn above the diagram. | |
| direction | No | Flow direction: 'right' (default) or 'down'. | right |
| save_path | No | Optional absolute path to write the .excalidraw file to. | |
| use_model | No | 'auto' uses the configured model and falls back to the offline rule parser, 'never' forces the offline parser, 'always' fails if no model is reachable. | auto |
| description | Yes | What to draw, e.g. 'A React app calls an API that reads Postgres and publishes to Kafka'. Arrow syntax like 'A -> B: label' also works. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses key behaviors: shapes laid out automatically, arrows bound to shapes, labels attached to containers, and optional file writing. However, it omits potential side effects such as file overwrite behavior if save_path exists, and does not mention failure modes.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three sentences, front-loaded with the core function. Each sentence earns its place: main action, output quality details, and optional file write. No wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool has 5 parameters and an output schema, the description gives a solid high-level understanding of the output (editable scene with bound arrows) and optional file write. It does not explain error conditions or model-specific usage, but the schema covers parameter details and the output schema likely covers return values.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description adds minimal parameter context by mentioning optional file writing (save_path), but does not elaborate on direction, title, or use_model beyond what the schema already provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Describe a system in plain English and get back a complete, editable Excalidraw scene' – a specific verb (get back) and resource (Excalidraw scene). It clearly distinguishes the creation function from sibling tools like validate_diagram and diagram_backend_status.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description clearly implies when to use the tool: when you need a diagram from a plain-English description. It sets context with details about layout and optional file writing, but does not explicitly mention when not to use it or reference alternatives like validate_diagram, so it lacks explicit exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
diagram_backend_statusReport which backend is availableA
Says whether a language model is configured or whether the server will use its offline rule parser. Useful for telling a downgrade apart from a deliberate offline run.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden. It transparently explains what the tool reports and adds interpretive value ('telling a downgrade apart from a deliberate offline run'), which goes beyond the title. It does not describe side effects or authorization needs, but for a read-only status check with zero parameters, this is adequate and not misleading.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two concise sentences with no superfluous content. The first sentence states the core function; the second adds practical value. It is front-loaded and every word earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple zero-parameter tool with an output schema, the description is complete. It explains what the tool does and why it's useful, and the existence of an output schema means the return values need not be described in the text. No gaps are apparent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the baseline is 4. The description does not need to explain parameters since there are none. The schema coverage is 100% (empty schema), and no parameter information is required.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: it reports whether a language model is configured or if the server will use the offline rule parser. This specific verb+resource (says/reports backend status) distinguishes it from siblings like create_diagram and validate_diagram, which perform different actions.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides a clear usage context: 'Useful for telling a downgrade apart from a deliberate offline run.' This implies when to use the tool (when you need to distinguish between a downgrade and an intentional offline mode), but it does not explicitly mention when not to use it or compare it to alternatives. Still, the guidance is sufficient given the simple nature of the tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
validate_diagramValidate an Excalidraw sceneA
Check an Excalidraw scene for schema errors, one-sided arrow bindings, labels whose container does not acknowledge them, arrows whose endpoints float away from the shapes they claim to be bound to, and overlapping shapes. Accepts the JSON itself or a path to a .excalidraw file.
| Name | Required | Description | Default |
|---|---|---|---|
| scene | Yes | The scene as a JSON string, or a path to a .excalidraw file. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the transparency burden. It adds specific details about the types of errors checked and accepted input formats, which is useful. However, it does not explicitly state that the operation is non-destructive or describe behavior on invalid input or file-not-found conditions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two concise sentences, front-loaded with the purpose and specific checks, with no redundant or extraneous information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With a single well-documented parameter and an existing output schema, the description covers the tool's purpose and input format effectively. Minor omissions about failure modes or side effects prevent a perfect score.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema fully documents the 'scene' parameter with the same content as the description. The description adds no extra semantic value beyond the schema, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function with a specific verb ('Check') and resource ('Excalidraw scene'), enumerating specific validation checks. This distinguishes it from siblings like create_diagram and diagram_backend_status.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use the tool (for validating a scene) but does not explicitly contrast it with alternatives or mention exclusions. Sibling tools clearly serve different purposes, so the lack of explicit alternatives is acceptable but not ideal.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
TDQS
Each tool serves a distinct purpose: creating diagrams, validating diagrams, and checking backend status. There is no overlap or ambiguity between them.
Two tools follow the verb_noun pattern (create_diagram, validate_diagram), while diagram_backend_status is more of a noun phrase. All use snake_case consistently, and the names are clear and descriptive.
With 3 tools, the server is well-scoped for the domain of diagram creation and validation. Each tool is essential and there is no bloat.
The core workflow of creating and validating diagrams is covered. Minor gaps exist such as no explicit update/delete tool for existing diagrams, but the 'editable scene' output and file writing mitigate this.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Create and edit architecture diagrams from your AI agent; get an SVG and a live editable canvas.
Generate cloud architecture diagrams, flowcharts, and sequence diagrams.
Render, validate, encode/decode PlantUML diagram-as-code; 22 diagram types. Free, no auth.
Generate dynamic Mermaid diagrams and charts with AI assistance. Customize styles and export diagr…
Related MCP Servers
- AlicenseAqualityCmaintenanceEnables AI agents to programmatically generate, edit, and view Excalidraw diagrams with real-time browser synchronization. It provides a suite of tools for adding shapes, text, and arrows to diagrams through natural language interactions.112,783100MIT
- FlicenseAqualityBmaintenanceGenerates beautiful Excalidraw diagrams from natural language descriptions using a local llama.cpp LLM, entirely offline.3
- AlicenseAqualityDmaintenanceGenerates Excalidraw architecture diagrams with support for 60+ components including GCP, Kafka, and AI/Agentic shapes. Provides MCP tools for creating, modifying, and converting diagrams from structured input or Mermaid syntax.41MIT
- AlicenseNot gradedqualityCmaintenanceProvides tools for creating, deleting, and querying nodes and edges in Excalidraw diagrams, enabling diagram editing via LLM interfaces.1295MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/dev48v/excalidraw-mcp-agent'
If you have feedback or need assistance with the MCP directory API, please join our Discord server