drawio-mcp
Draw.io MCP — Diagram Creation & Editing
You are an expert at creating and editing draw.io diagrams via the draw.io MCP server. Diagrams appear in real-time in the user's browser.
Critical: These Are Direct Tool Calls
MCP tools are direct tool calls — NOT CLI commands.
All draw.io MCP tools use the mcp__drawio__ prefix.
Mandatory Workflow
1. start_session ← always first (opens browser)
2. create_new_diagram ← for new diagrams (replaces entire diagram)
OR
get_diagram ← REQUIRED before edit_diagram
edit_diagram ← for modifications (preserves user's manual edits)
3. export_diagram ← optional, saves to .drawio / .png / .svg
Rules:
start_sessionmust be called before any other tool in a new sessionget_diagramMUST be called beforeedit_diagram— skipping it will silently overwrite the user's manual changes. The server enforces a 30-second window; after 30s you must callget_diagramagain.create_new_diagramreplaces the ENTIRE diagram — only use for new diagrams or complete redrawsedit_diagramis for targeted adds/updates/deletes to an existing diagram
XML Format
Every diagram is a complete mxGraphModel:
<mxGraphModel>
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<!-- all cells go here, parent="1" for top-level -->
<mxCell id="2" value="Label" style="..." vertex="1" parent="1">
<mxGeometry x="100" y="100" width="120" height="40" as="geometry"/>
</mxCell>
</root>
</mxGraphModel>
Layout rules:
- Keep everything within x=0–800, y=0–600 for single-page viewport
- IDs start at "2" (0 and 1 are reserved)
- Space shapes 150–200px apart for clean edge routing
Semantic Design System
Default for workflow, pipeline, and architecture diagrams. Ported from the hand-crafted SVG design system — consistent visual language across all diagrams. Use this unless the user asks for a different theme.
Node Styles
| Role | Full draw.io style |
|---|---|
| Action — planning (blue) | rounded=1;fillColor=#ffffff;strokeColor=#3b82f6;fontColor=#2563eb;fontSize=13;fontStyle=1;shadow=1; |
| Action — builder (purple) | rounded=1;fillColor=#ffffff;strokeColor=#8b5cf6;fontColor=#7c3aed;fontSize=13;fontStyle=1;shadow=1; |
| Action — validator (green) | rounded=1;fillColor=#ffffff;strokeColor=#22c55e;fontColor=#166534;fontSize=13;fontStyle=1;shadow=1; |
| Action — neutral (gray) | rounded=1;fillColor=#ffffff;strokeColor=#6b7280;fontColor=#374151;fontSize=13;fontStyle=1;shadow=1; |
| Decision diamond | rhombus;fillColor=#ffffff;strokeColor=#6b7280;fontColor=#374151;fontSize=11; |
| Done pill (terminal success) | rounded=1;arcSize=50;fillColor=#dcfce7;strokeColor=#16a34a;fontColor=#15803d;fontSize=13;fontStyle=1;shadow=1; |
| Phase done | rounded=1;fillColor=#f0fdf4;strokeColor=#22c55e;fontColor=#166534;fontSize=13;shadow=1; |
| Annotation callout | rounded=1;fillColor=#fefce8;strokeColor=#eab308;fontColor=#a16207;fontSize=11;dashed=1; |
Group / Container Styles
Use as swim-lane or container shapes (set vertex=1 with large geometry to act as a background region):
| Role | Full draw.io style |
|---|---|
| Planning group (blue) | rounded=1;fillColor=#eff6ff;gradientColor=#dbeafe;gradientDirection=south;strokeColor=#93c5fd;strokeWidth=1.5;fontSize=11;fontStyle=1;fontColor=#1d4ed8;verticalAlign=top;shadow=1; |
| Builder group (purple, dashed) | rounded=1;fillColor=#faf5ff;gradientColor=#f3e8ff;gradientDirection=south;strokeColor=#a78bfa;strokeWidth=1.5;fontSize=11;fontStyle=1;fontColor=#7c3aed;verticalAlign=top;dashed=1; |
| Validator group (green, dashed) | rounded=1;fillColor=#f0fdf4;gradientColor=#dcfce7;gradientDirection=south;strokeColor=#4ade80;strokeWidth=1.5;fontSize=11;fontStyle=1;fontColor=#15803d;verticalAlign=top;dashed=1; |
| Outer container (gray) | rounded=1;fillColor=#fafafa;strokeColor=#d1d5db;strokeWidth=1.5;fontSize=11;fontStyle=1;fontColor=#374151;verticalAlign=top;shadow=1; |
Edge Styles (Semantic)
| Meaning | Full draw.io style |
|---|---|
| Neutral flow | endArrow=block;endFill=1;strokeColor=#6b7280;strokeWidth=1.5;edgeStyle=orthogonalEdgeStyle; |
| Pass / success | endArrow=block;endFill=1;strokeColor=#22c55e;strokeWidth=1.5;edgeStyle=orthogonalEdgeStyle; |
| Fail / error | endArrow=block;endFill=1;strokeColor=#ef4444;strokeWidth=1.5;edgeStyle=orthogonalEdgeStyle; |
| Fix / retry | endArrow=block;endFill=1;strokeColor=#d97706;strokeWidth=1.5;edgeStyle=orthogonalEdgeStyle; |
| Annotation link (dashed, no arrow) | endArrow=none;strokeColor=#eab308;strokeWidth=1;dashed=1;dashPattern=4 3; |
Typography (fontStyle bitmask: 1=bold, 2=italic, 4=underline)
| Role | fontSize | fontStyle | fontColor |
|---|---|---|---|
| Group title | 11 | 1 (bold) | Phase color |
| Primary node text | 13 | 1 (bold) | Phase color |
| Subtitle / secondary | 11 | 0 | #6b7280 |
| Edge label | 11 | 1 (bold) | Semantic color |
Semantic Color Reference
| Role | Fill | Stroke | Text |
|---|---|---|---|
| Blue (planning) | #ffffff |
#3b82f6 |
#2563eb |
| Purple (builder) | #ffffff |
#8b5cf6 |
#7c3aed |
| Green (validator/pass) | #ffffff |
#22c55e |
#166534 |
| Gray (neutral) | #ffffff |
#6b7280 |
#374151 |
| Red (fail) | — | #ef4444 |
#dc2626 |
| Amber (fix/retry) | — | #d97706 |
#d97706 |
| Yellow (annotation) | #fefce8 |
#eab308 |
#a16207 |
| Done pill | #dcfce7 |
#16a34a |
#15803d |
Alternative Palettes
Use when the user explicitly requests a different visual style.
Dark / Tech
nodes: fillColor=#1e1e2e;strokeColor=#89b4fa;fontColor=#cdd6f4
accents: strokeColor=#a6e3a1 (green), #f38ba8 (red), #cba6f7 (purple)
Pastel / Soft
nodes: fillColor=#dae8fc;strokeColor=#6c8ebf;fontColor=#333333
Minimal / Mono
nodes: fillColor=#ffffff;strokeColor=#333333;fontColor=#333333
edges: endArrow=open;endSize=8;strokeColor=#333333
Bold / AWS
header: fillColor=#232F3E;strokeColor=#FF9900;fontColor=#ffffff
compute: fillColor=#FF9900;strokeColor=#FF9900;fontColor=#ffffff
Vibrant / UI
primary: fillColor=#6366f1;strokeColor=#4f46e5;fontColor=#ffffff;shadow=1
secondary: fillColor=#8b5cf6;strokeColor=#7c3aed;fontColor=#ffffff;shadow=1
Common Shape Styles
| Shape | Style fragment |
|---|---|
| Rounded rectangle | rounded=1; |
| Diamond (decision) | rhombus; |
| Pill (terminal) | rounded=1;arcSize=50; |
| Cylinder (database) | shape=cylinder3; |
| Circle | ellipse; |
| User/person | shape=mxgraph.aws4.user; |
| Cloud | shape=mxgraph.aws4.cloud; |
| Title text | text;fontSize=16;fontStyle=1;align=center; |
Layout Rules (Critical — violations cause misaligned diagrams)
1. Center-align all nodes in a flow column
Every node in a vertical flow column must share the same center_x. Mixed center_x values cause orthogonal edges to jog horizontally, routing through text.
Formula: node_x = center_x - node_width / 2
For a container at x=C_x, width=C_w: center_x = C_x + C_w / 2
If subgroups inside the container have a fixed center (e.g. builder nodes at center_x=533), align ALL orchestrator nodes above/below them to that same center_x. Do not place orchestrator nodes at a different x and rely on routing to bridge the gap.
2. Edges between vertically-stacked nodes must be straight vertical
If source and target share the same center_x, use exitX=0.5;exitY=1;entryX=0.5;entryY=0; — the edge routes as a clean vertical line with no horizontal jog.
If they have different center_x values (unavoidable), add an explicit waypoint that steps horizontally above the entry node (at y = target_top - 15) so the jog happens in empty space, not through text:
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="[target_center_x]" y="[target_top - 15]"/>
</Array>
</mxGeometry>
3. Annotation boxes: vertical center must match the connector exit point
For horizontal dashed connectors to annotation boxes, the annotation's vertical center must equal the source element's exit y.
Formula: annotation_y = source_center_y - annotation_height / 2
Example: source diamond center_y=234, annotation height=72 → annotation_y = 234 - 36 = 198.
If the annotation y is wrong the connector angles — it will not be horizontal. Calculate this explicitly before placing annotations.
4. Loopback labels: use edge value, not rotated text cells
Do NOT use standalone mxCell text cells with rotation=-90 as sidebar labels for loopback edges. They render as floating horizontal blocks, not clean sidebar annotations.
Do: Put the label as the edge value — it will appear near the midpoint of the edge in horizontal text, which is readable and unambiguous:
<mxCell id="e-fail" value="FAIL" style="...strokeColor=#ef4444;fontColor=#dc2626;fontSize=11;fontStyle=1;..." edge="1" ...>
For loopbacks with two semantic labels (e.g. "FAIL" on horizontal segment, "Fresh builder" on vertical), use the more important label as value and omit the secondary label.
Edge Routing Rules
- Always specify
exitX,exitY,entryX,entryYexplicitly — never rely on auto-routing to pick correct connection points - For bidirectional connections (A↔B), use opposite sides (exitY=0.3 / entryY=0.7)
- Never let multiple edges share the same path — offset using different exit/entry points
- Add
curved=1;for smoother bends on complex routes
<!-- Example: clean vertical edge between aligned nodes -->
<mxCell id="e1" value="" style="endArrow=block;endFill=1;strokeColor=#6b7280;strokeWidth=1.5;edgeStyle=orthogonalEdgeStyle;exitX=0.5;exitY=1;entryX=0.5;entryY=0;" edge="1" source="node-a" target="node-b" parent="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<!-- Example: edge stepping around text via waypoint -->
<mxCell id="e2" value="" style="endArrow=block;endFill=1;strokeColor=#22c55e;strokeWidth=1.5;edgeStyle=orthogonalEdgeStyle;exitX=0.5;exitY=1;entryX=0.5;entryY=0;" edge="1" source="diamond" target="inner-node" parent="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="[inner_node_center_x]" y="[inner_node_top - 15]"/>
</Array>
</mxGeometry>
</mxCell>
edit_diagram Operations
{ "operations": [
{ "operation": "add", "cell_id": "new-1", "new_xml": "<mxCell ...>" },
{ "operation": "update", "cell_id": "2", "new_xml": "<mxCell ...>" },
{ "operation": "delete", "cell_id": "old-1" }
]}
Always use descriptive cell_id values (e.g. "lambda-fn", "api-gw") — not numeric IDs — for new cells to avoid collisions.
Export
export_diagram({ path: "./diagram.drawio" }) ← XML (default)
export_diagram({ path: "./diagram.png" }) ← PNG (requires open browser tab)
export_diagram({ path: "./diagram.svg" }) ← SVG (requires open browser tab)
PNG/SVG export requires the browser tab to be open and the diagram loaded.
Port & Session Notes
- MCP server uses port 6002 by default; auto-increments to 6003–6020 if occupied
- The next-ai-draw-io desktop app uses port 61337 in production — no conflict
- In dev mode (
npm run dev) the desktop app also uses 6002 — conflict likely; setPORT=6003in MCP env - The MCP server and the desktop app are separate — the MCP controls a browser-based draw.io embed, not the Electron window
Configuration
| Env var | Default | Purpose |
|---|---|---|
PORT |
6002 |
MCP embedded server port |
DRAWIO_BASE_URL |
https://embed.diagrams.net |
draw.io embed source (for self-hosted) |
Decision Tree
| User says | Action |
|---|---|
| "Create a diagram" | start_session → create_new_diagram |
| "Add X to the diagram" | get_diagram → edit_diagram (add) |
| "Change / update X" | get_diagram → edit_diagram (update) |
| "Remove X" | get_diagram → edit_diagram (delete) |
| "Save / export" | export_diagram |
| Asks about style | Apply named palette from this skill; show options if unsure |
Troubleshooting
"No active session"
Call start_session first — the session resets on MCP server restart.
Browser not updating
Check the browser URL contains ?mcp=<session-id>. If the tab was closed, call start_session again to get a new URL.
Port already in use
Set PORT=6003 in the MCP server env config (.mcp.json or Claude Desktop config).
edit_diagram rejected ("must call get_diagram first")
The 30-second window expired. Call get_diagram then retry edit_diagram immediately.
PNG/SVG export returns "timed out"
The browser tab must be open with the diagram loaded. Navigate to the session URL, wait for the diagram to render, then retry.
More from darraghh1/my-claude-setup
playwright-mcp
Live browser interaction via Playwright MCP — navigate pages, click buttons, fill forms, take screenshots.
97tavily-mcp
Web search, content extraction, site crawling, and multi-source research via the Tavily MCP server.
27react-form-builder
Create client-side forms with react-hook-form, shadcn/ui, Zod validation, and server action integration for Next.js applications. Use when building forms, input validation, or 'create/edit' UI flows. Do NOT use for non-form components — use /vercel-react-best-practices instead.
26service-builder
Build pure, interface-agnostic services with injected dependencies for Next.js/Supabase applications. Use when creating service layers, business logic classes, or CRUD operations. Do NOT use for server actions — use /server-action-builder instead.
25code-review
Review code for quality, security, and pattern compliance, then auto-fix Critical/High issues. Grounds every finding in actual codebase reference files. Use when asked to 'review the code', 'check quality', or after implementation phases complete. Do NOT use for plan reviews — use /review-plan instead.
25sequential-thinking-mcp
Structured multi-step reasoning via Sequential Thinking MCP. Use for complex debugging, architectural trade-offs, or root cause analysis.
24