Draw.io Architecture Diagrams
Generate Azure architecture diagrams in .drawio format using the
simonkurtz-MSFT Draw.io MCP server. The server ships the full Azure icon set
(see assets/azure-public-service-icons/),
fuzzy shape search, batch operations, group/layer/page management, and
transactional mode for efficient multi-step workflows.
The MCP server's own src/instructions.md is the authoritative tool reference;
it is auto-sent to the client at startup. This skill captures project-specific
conventions that complement (not duplicate) it.
Naming note: "drawio" can refer to (a) this skill, (b) the MCP server slug
simonkurtz-MSFT/drawio-mcp-server, or (c) the mcp_drawio_* tool family. In
agent-facing references, disambiguate explicitly — say "the drawio skill" or
"the drawio MCP server", not bare drawio.
Prerequisites
- MCP server:
simonkurtz-MSFT/drawio-mcp-server (Deno, stdio) configured in .vscode/mcp.json
- Deno runtime: installed via devcontainer feature
- VS Code extension (optional):
hediet.vscode-drawio for in-editor preview
MCP Workflow Summary
The MCP server's startup src/instructions.md is the authoritative tool reference. The
table below lists the most-used tools and the repo-specific batch sequence. Reusable call
patterns: references/azure-patterns.md.
| Tool |
Purpose |
search-shapes |
Fuzzy-search the Azure icon library; resolves names to shapes |
create-groups |
Create container cells (VNets, subnets, resource groups, envs) |
add-cells |
Add vertices + edges in a single batch (use shape_name, temp_id) |
add-cells-to-group |
Assign children to group containers |
edit-cells / edit-edges |
Update cell or edge properties post-creation |
validate-group-containment |
Detect children that exceed group bounds |
finish-diagram |
Resolve transactional placeholders + emit final compressed XML |
export-diagram |
Non-transactional export with compress: true |
Standard sequence: search-shapes → create-groups → add-cells → add-cells-to-group
→ (optional edit-*) → validate-group-containment → finish-diagram /
export-diagram (compress: true).
import-diagram input contract (CRITICAL — Phase D3 of nordic-foods
lessons plan): when calling import-diagram (or any tool whose schema
declares an xml parameter), the field MUST be XML content as a
string — never a file path. Passing a bare path/to/file.drawio
string produces INVALID_XML from the server and burns an MCP round
trip. If you have a path on disk:
WRONG: import-diagram(xml="agent-output/foo/03-des-diagram.drawio")
RIGHT: read_file("agent-output/foo/03-des-diagram.drawio") → import-diagram(xml=<content>)
Mirror this warning in 04-design.agent.md next to every
import-diagram reference. The two locations must stay in sync.
CLI Fallback
There is no programmatic CLI fallback for diagram authoring. The Draw.io desktop app
is the only manual alternative; if the MCP server is unavailable, stop and surface the
failure rather than hand-rolling XML. The tools/scripts/save-drawio.py and
cleanup-drawio.py helpers are post-processing utilities for MCP output, not authoring
fallbacks.
Icon Handling
Icons are resolved automatically by the MCP server from its built-in library
(the full Azure icon set bundled with the server).
shape_name in add-cells specifies an Azure icon (e.g., "Front Doors").
Do NOT pass width, height, or style alongside it — the server applies them.
search-shapes with a queries array finds icon names by fuzzy match.
- Azure icons use official service names, often plural (
"Key Vaults", "Container Apps").
- Every shaped vertex MUST have a
text label or omit text entirely — never pass "".
- Output format is embedded base64 SVG in the style attribute.
Diagram Creation Workflows
Two modes — non-transactional (small diagrams, full XML each call) and
transactional (recommended for multi-step; lightweight placeholders during
the loop, real SVGs resolved by finish-diagram at the end). Full call chains,
the save-drawio.py save procedure, and the post-save cleanup script live in
references/creation-workflows.md.
Critical: transactional mode MUST end with finish-diagram(compress: true)
or the saved diagram keeps placeholder cells instead of real Azure icons.
Rules
- Batch-only workflow — every tool that accepts an array MUST be called exactly ONCE with all items; never call a tool repeatedly for individual items (see Batch-Only Workflow (CRITICAL) below)
- Use
shape_name for Azure icons — do NOT pass width, height, or style alongside it; the server applies them
- Every shaped vertex MUST have a
text label or omit text entirely — never pass ""
- Vertices first in
add-cells — edges must be ordered after the vertices they reference
- Transactional mode for multi-step diagrams — use placeholders +
finish-diagram at the end (~2KB intermediate vs ~200KB)
- Use
compress: true on export-diagram / finish-diagram to keep .drawio files small
- Do NOT pipe large MCP JSON back through the LLM — use
python3 tools/scripts/save-drawio.py to extract via terminal
- Out of scope: WAF / cost charts (use
python-diagrams), inline Mermaid (use mermaid)
Steps
Every tool that accepts an array MUST be called exactly ONCE with all items. Never call a tool repeatedly for individual items.
search-shapes — ONE call with all queries (main flow + cross-cutting)
create-groups — ONE call with all groups. Set text: "" and create a separate text vertex above each group
add-cells — ONE call with all vertices AND edges, vertices first. Use temp_id for cross-refs, shape_name for icons
add-cells-to-group — ONE call with all assignments
edit-cells / edit-edges — ONE call if adjustments are needed
finish-diagram (transactional) or export-diagram (default) — with compress: true
After group assignments, call validate-group-containment to detect children that exceed group bounds.
Token efficiency
- MCP server is NOT stateful — pass
diagram_xml from the previous call on every subsequent call. Save XML to a temp file between steps; read only the IDs you need rather than the whole JSON.
- Never read back large MCP responses through the LLM — extract data via terminal commands.
- Target 8–10 model turns for a complete diagram. Pre-compute the full layout before making any MCP calls.
Layout Conventions
Concise summary; load references/style-reference.md → "Layout Conventions (extended)" for full detail (numbered callouts, fan-out staggering, legend HTML, group sizing, non-Azure component styling).
- Primary flow: left-to-right; parallel services stacked vertically per column
- Spacing minimums: 120px between columns, 80px between rows, 40px around each cell; groups need ≥150px width per icon
- Page: US Letter 850×1100px (extend to 1300px if a legend is included); 40px margins
- Edges: orthogonal only (
edgeStyle=orthogonalEdgeStyle); never set entryX/Y / exitX/Y and never add <Array as="points"> waypoints. Target specific icons inside groups, not the group cell
- Cross-cutting services (Azure Monitor, Entra ID, Key Vault, Defender): single light-grey rounded container at the bottom, 120px apart, no edges into them
- Legend: required on every diagram, below the cross-cutting box; use inline HTML for arrow indicators; explicitly set
text: "" on shape samples
- External actors (Users, Operators): outside all group boundaries
Edge post-processing (CRITICAL): After finish-diagram, run tools/scripts/save-drawio.py to strip auto-router anchors and waypoints so Draw.io can recalculate clean orthogonal paths. The post-save cleanup script (cleanup-drawio.py) is documented in references/creation-workflows.md.
Gotchas
text: "" breaks shapes — every shaped vertex MUST have a text label
or omit text entirely; never pass "".
- No dimensions with
shape_name — never pass width, height, or style
when using shape_name; the MCP server auto-applies correct values.
- Transactional mode MUST end with
finish-diagram — otherwise the diagram
keeps ~2KB placeholders instead of real SVG icons.
shape=image + image=data:image/svg+xml;base64,… is the RESOLVED form —
do NOT confuse it with placeholder=1. After finish-diagram(compress: true),
every Azure icon appears as shape=image;…;image=data:image/svg+xml;base64,<svg>
with a multi-path Azure-brand SVG inside. The validator counts these as
totalImages (real icons). The placeholder=1 style attribute is the ONLY
marker of an unresolved transactional cell — count it with
grep -c 'placeholder=1' file.drawio before declaring a diagram broken.
- Never read large MCP responses through the LLM — extract data via terminal
(Python script) to avoid context-window inflation.
- Batch-only workflow — every tool accepting arrays is called ONCE with ALL items.
- No edge anchors or waypoints — never set
entryX/Y, exitX/Y, or add
<Array as="points"> to edges.
Reference Index
| File |
Purpose |
references/style-reference.md |
Draw.io style properties for AI-generated files |
references/azure-patterns.md |
Reusable MCP tool call patterns for Azure architectures |
references/validation-checklist.md |
Validation rules for AI-generated .drawio files |
references/abstraction-rules.md |
Diagram abstraction and data-flow clarity rules |
references/iac-to-diagram.md |
Generate diagrams from Bicep/Terraform/ARM templates |
references/quality-rubric.md |
Canonical 0–4 quality rubric (7 dimensions, thresholds) |
references/semantic-zones.md |
Subscription / region / trust-boundary / external zone templates |
references/diagram-types.md |
Logical / network / sequence / deployment selection + signatures |
references/legend-template.md |
Copy-pasteable legend block (inline + two-column variants) |
references/icon-variants.md |
Service tier / SKU disambiguation + single-batch contract |
references/large-architecture-decomposition.md |
Tier S/M/L/XL breakpoints, decomposition, density target |
Quality Reference Examples
| File |
Pattern |
examples/azure-vm-baseline-architecture.drawio |
VM baseline — VNet + 6 subnets, vertical flow, legend |
examples/azure-aks-microservices.drawio |
AKS microservices — horizontal flow, namespaces, CI/CD |
examples/azure-dns-private-resolver.drawio |
DNS Private Resolver — hub-spoke, numbered callouts |
examples/azure-foundry-landing-zone.drawio |
Foundry Chat — landing zone, multi-subscription |
examples/azure-vm-baseline-architecture.svg |
Source SVG from Microsoft Learn (reference comparison) |
1---2name: drawio3description: **WORKFLOW SKILL** — Generate Azure architecture diagrams in .drawio via simonkurtz-MSFT MCP server (full Azure icon set, batch creation, transactional mode). Covers architecture, dependency, runtime-flow, and as-built diagrams. WHEN: 'draw.io diagram', 'Azure architecture diagram', 'as-built diagram', 'runtime flow diagram', 'dependency diagram'. DO NOT USE FOR: WAF/cost charts (python-diagrams), inline Mermaid (mermaid).4license: MIT5---67# Draw.io Architecture Diagrams89Generate Azure architecture diagrams in `.drawio` format using the10simonkurtz-MSFT Draw.io MCP server. The server ships the full Azure icon set11(see [`assets/azure-public-service-icons/`](../../../assets/drawio-libraries/azure-icons)),12fuzzy shape search, batch operations, group/layer/page management, and13transactional mode for efficient multi-step workflows.1415The MCP server's own `src/instructions.md` is the authoritative tool reference;16it is auto-sent to the client at startup. This skill captures project-specific17conventions that complement (not duplicate) it.1819> **Naming note**: "drawio" can refer to (a) this skill, (b) the MCP server slug20> `simonkurtz-MSFT/drawio-mcp-server`, or (c) the `mcp_drawio_*` tool family. In21> agent-facing references, disambiguate explicitly — say "the `drawio` skill" or22> "the drawio MCP server", not bare `drawio`.2324## Prerequisites2526- **MCP server**: `simonkurtz-MSFT/drawio-mcp-server` (Deno, stdio) configured in `.vscode/mcp.json`27- **Deno runtime**: installed via devcontainer feature28- **VS Code extension** (optional): `hediet.vscode-drawio` for in-editor preview2930## MCP Workflow Summary3132The MCP server's startup `src/instructions.md` is the authoritative tool reference. The33table below lists the most-used tools and the repo-specific batch sequence. Reusable call34patterns: [`references/azure-patterns.md`](references/azure-patterns.md).3536| Tool | Purpose |37| ---------------------------- | -------------------------------------------------------------------- |38| `search-shapes` | Fuzzy-search the Azure icon library; resolves names to shapes |39| `create-groups` | Create container cells (VNets, subnets, resource groups, envs) |40| `add-cells` | Add vertices + edges in a single batch (use `shape_name`, `temp_id`) |41| `add-cells-to-group` | Assign children to group containers |42| `edit-cells` / `edit-edges` | Update cell or edge properties post-creation |43| `validate-group-containment` | Detect children that exceed group bounds |44| `finish-diagram` | Resolve transactional placeholders + emit final compressed XML |45| `export-diagram` | Non-transactional export with `compress: true` |4647Standard sequence: `search-shapes` → `create-groups` → `add-cells` → `add-cells-to-group`48→ (optional `edit-*`) → `validate-group-containment` → `finish-diagram` /49`export-diagram` (`compress: true`).5051> **`import-diagram` input contract (CRITICAL — Phase D3 of nordic-foods52> lessons plan)**: when calling `import-diagram` (or any tool whose schema53> declares an `xml` parameter), the field **MUST be XML content as a54> string** — never a file path. Passing a bare `path/to/file.drawio`55> string produces `INVALID_XML` from the server and burns an MCP round56> trip. If you have a path on disk:57>58> ```text59> WRONG: import-diagram(xml="agent-output/foo/03-des-diagram.drawio")60> RIGHT: read_file("agent-output/foo/03-des-diagram.drawio") → import-diagram(xml=<content>)61> ```62>63> Mirror this warning in `04-design.agent.md` next to every64> `import-diagram` reference. The two locations must stay in sync.6566## CLI Fallback6768**There is no programmatic CLI fallback for diagram authoring.** The Draw.io desktop app69is the only manual alternative; if the MCP server is unavailable, stop and surface the70failure rather than hand-rolling XML. The `tools/scripts/save-drawio.py` and71`cleanup-drawio.py` helpers are post-processing utilities for MCP output, not authoring72fallbacks.7374## Icon Handling7576Icons are resolved automatically by the MCP server from its built-in library77(the full Azure icon set bundled with the server).7879- `shape_name` in `add-cells` specifies an Azure icon (e.g., `"Front Doors"`).80 **Do NOT** pass `width`, `height`, or `style` alongside it — the server applies them.81- `search-shapes` with a `queries` array finds icon names by fuzzy match.82- Azure icons use official service names, often plural (`"Key Vaults"`, `"Container Apps"`).83- Every shaped vertex MUST have a `text` label or omit `text` entirely — never pass `""`.84- Output format is embedded base64 SVG in the style attribute.8586## Diagram Creation Workflows8788Two modes — **non-transactional** (small diagrams, full XML each call) and89**transactional** (recommended for multi-step; lightweight placeholders during90the loop, real SVGs resolved by `finish-diagram` at the end). Full call chains,91the `save-drawio.py` save procedure, and the post-save cleanup script live in92[`references/creation-workflows.md`](references/creation-workflows.md).9394> **Critical**: transactional mode MUST end with `finish-diagram(compress: true)`95> or the saved diagram keeps placeholder cells instead of real Azure icons.9697## Rules9899- **Batch-only workflow** — every tool that accepts an array MUST be called exactly ONCE with all items; never call a tool repeatedly for individual items (see [Batch-Only Workflow (CRITICAL)](#batch-only-workflow-critical) below)100- **Use `shape_name` for Azure icons** — do NOT pass `width`, `height`, or `style` alongside it; the server applies them101- **Every shaped vertex MUST have a `text` label or omit `text` entirely** — never pass `""`102- **Vertices first in `add-cells`** — edges must be ordered after the vertices they reference103- **Transactional mode for multi-step diagrams** — use placeholders + `finish-diagram` at the end (~2KB intermediate vs ~200KB)104- **Use `compress: true`** on `export-diagram` / `finish-diagram` to keep `.drawio` files small105- **Do NOT pipe large MCP JSON back through the LLM** — use `python3 tools/scripts/save-drawio.py` to extract via terminal106- **Out of scope**: WAF / cost charts (use `python-diagrams`), inline Mermaid (use `mermaid`)107108## Steps109110**Every tool that accepts an array MUST be called exactly ONCE with all items.** Never call a tool repeatedly for individual items.1111121. `search-shapes` — ONE call with all queries (main flow + cross-cutting)1132. `create-groups` — ONE call with all groups. Set `text: ""` and create a separate text vertex above each group1143. `add-cells` — ONE call with all vertices AND edges, **vertices first**. Use `temp_id` for cross-refs, `shape_name` for icons1154. `add-cells-to-group` — ONE call with all assignments1165. `edit-cells` / `edit-edges` — ONE call if adjustments are needed1176. `finish-diagram` (transactional) or `export-diagram` (default) — with `compress: true`118119After group assignments, call `validate-group-containment` to detect children that exceed group bounds.120121### Token efficiency122123- **MCP server is NOT stateful** — pass `diagram_xml` from the previous call on every subsequent call. Save XML to a temp file between steps; read only the IDs you need rather than the whole JSON.124- **Never read back large MCP responses through the LLM** — extract data via terminal commands.125- **Target 8–10 model turns** for a complete diagram. Pre-compute the full layout before making any MCP calls.126127## Layout Conventions128129Concise summary; load [`references/style-reference.md`](references/style-reference.md) → "Layout Conventions (extended)" for full detail (numbered callouts, fan-out staggering, legend HTML, group sizing, non-Azure component styling).130131- **Primary flow**: left-to-right; parallel services stacked vertically per column132- **Spacing minimums**: 120px between columns, 80px between rows, 40px around each cell; groups need ≥150px width per icon133- **Page**: US Letter 850×1100px (extend to 1300px if a legend is included); 40px margins134- **Edges**: orthogonal only (`edgeStyle=orthogonalEdgeStyle`); never set `entryX/Y` / `exitX/Y` and never add `<Array as="points">` waypoints. Target specific icons inside groups, not the group cell135- **Cross-cutting services** (Azure Monitor, Entra ID, Key Vault, Defender): single light-grey rounded container at the bottom, 120px apart, no edges into them136- **Legend**: required on every diagram, below the cross-cutting box; use inline HTML for arrow indicators; explicitly set `text: ""` on shape samples137- **External actors** (Users, Operators): outside all group boundaries138139> **Edge post-processing (CRITICAL)**: After `finish-diagram`, run `tools/scripts/save-drawio.py` to strip auto-router anchors and waypoints so Draw.io can recalculate clean orthogonal paths. The post-save cleanup script (`cleanup-drawio.py`) is documented in [`references/creation-workflows.md`](references/creation-workflows.md).140141## Gotchas142143- **`text: ""` breaks shapes** — every shaped vertex MUST have a `text` label144 or omit `text` entirely; never pass `""`.145- **No dimensions with `shape_name`** — never pass `width`, `height`, or `style`146 when using `shape_name`; the MCP server auto-applies correct values.147- **Transactional mode MUST end with `finish-diagram`** — otherwise the diagram148 keeps ~2KB placeholders instead of real SVG icons.149- **`shape=image` + `image=data:image/svg+xml;base64,…` is the RESOLVED form** —150 do NOT confuse it with `placeholder=1`. After `finish-diagram(compress: true)`,151 every Azure icon appears as `shape=image;…;image=data:image/svg+xml;base64,<svg>`152 with a multi-path Azure-brand SVG inside. The validator counts these as153 `totalImages` (real icons). The `placeholder=1` style attribute is the ONLY154 marker of an unresolved transactional cell — count it with155 `grep -c 'placeholder=1' file.drawio` before declaring a diagram broken.156- **Never read large MCP responses through the LLM** — extract data via terminal157 (Python script) to avoid context-window inflation.158- **Batch-only workflow** — every tool accepting arrays is called ONCE with ALL items.159- **No edge anchors or waypoints** — never set `entryX/Y`, `exitX/Y`, or add160 `<Array as="points">` to edges.161162## Reference Index163164| File | Purpose |165| ------------------------------------------------ | ---------------------------------------------------------------- |166| `references/style-reference.md` | Draw.io style properties for AI-generated files |167| `references/azure-patterns.md` | Reusable MCP tool call patterns for Azure architectures |168| `references/validation-checklist.md` | Validation rules for AI-generated `.drawio` files |169| `references/abstraction-rules.md` | Diagram abstraction and data-flow clarity rules |170| `references/iac-to-diagram.md` | Generate diagrams from Bicep/Terraform/ARM templates |171| `references/quality-rubric.md` | Canonical 0–4 quality rubric (7 dimensions, thresholds) |172| `references/semantic-zones.md` | Subscription / region / trust-boundary / external zone templates |173| `references/diagram-types.md` | Logical / network / sequence / deployment selection + signatures |174| `references/legend-template.md` | Copy-pasteable legend block (inline + two-column variants) |175| `references/icon-variants.md` | Service tier / SKU disambiguation + single-batch contract |176| `references/large-architecture-decomposition.md` | Tier S/M/L/XL breakpoints, decomposition, density target |177178### Quality Reference Examples179180| File | Pattern |181| ------------------------------------------------ | ------------------------------------------------------ |182| `examples/azure-vm-baseline-architecture.drawio` | VM baseline — VNet + 6 subnets, vertical flow, legend |183| `examples/azure-aks-microservices.drawio` | AKS microservices — horizontal flow, namespaces, CI/CD |184| `examples/azure-dns-private-resolver.drawio` | DNS Private Resolver — hub-spoke, numbered callouts |185| `examples/azure-foundry-landing-zone.drawio` | Foundry Chat — landing zone, multi-subscription |186| `examples/azure-vm-baseline-architecture.svg` | Source SVG from Microsoft Learn (reference comparison) |