Skip to main content
Glama
README.md
# excalidraw-mcp

An MCP ([Model Context Protocol](https://modelcontextprotocol.io)) server for [Excalidraw](https://excalidraw.com). It lets an AI agent build, edit, organize, and export Excalidraw scenes — architecture diagrams, flowcharts, codebase maps, whiteboards — entirely headless, producing `.excalidraw` files you can open at excalidraw.com, plus SVG/PNG renders in Excalidraw's hand-drawn style.

<p align="center"><img src="examples/flowchart.png" width="420" alt="Flowchart generated by the smoke test" /></p>

## Features

- **Every element type**: rectangles, ellipses, diamonds, text, lines, arrows, freedraw strokes, frames, embedded images, and embeddables (iframes)
- **Real Excalidraw semantics**: bound labels (text inside shapes / on arrows), arrow ↔ shape bindings that survive dragging in the UI, groups, frames, z-order, lock state, fractional indices
- **One-shot diagrams**: `create_flowchart` lays out labeled nodes and bound edges automatically (layered layout, `down` or `right`)
- **Full editing surface**: update, move, resize, duplicate (with binding remap), align, distribute, group, reorder, query
- **Overlap-free by default**: creation tools nudge new elements to free space (`avoidOverlap: false` to layer intentionally), `resolve_overlaps` spreads out colliding elements, and bound arrows re-route automatically after moves
- **Persistence & export**: `.excalidraw` files (v2), `.excalidrawlib` libraries, SVG and PNG rendering (roughjs + perfect-freehand, so it *looks* like Excalidraw)
- **All three MCP primitives**: 42 tools, resources (`excalidraw://scenes`, `excalidraw://scene/{id}`, `excalidraw://scene/{id}/svg`), and prompts (`architecture-diagram`, `flowchart`, `annotate-scene`)

## Setup

```bash
npm install
npm run build
```

### Claude Code

```bash
claude mcp add excalidraw -- node /path/to/excalidraw-mcp/dist/index.js
```

(This repo also ships a project-scoped `.mcp.json`, so opening the repo in Claude Code registers the server automatically.)

### Claude Desktop

```jsonc
// claude_desktop_config.json
{
  "mcpServers": {
    "excalidraw": {
      "command": "node",
      "args": ["/path/to/excalidraw-mcp/dist/index.js"]
    }
  }
}
```

## Tools

| Group | Tools |
| --- | --- |
| Scenes | `create_scene` `list_scenes` `switch_scene` `get_scene` `describe_scene` `clear_scene` `delete_scene` `set_app_state` `save_scene` `load_scene` `unlock_all` |
| Create | `add_shape` `add_text` `add_line` `add_arrow` `add_freedraw` `add_frame` `add_image` `add_embed` `add_elements` |
| Edit | `get_element` `find_elements` `update_element` `delete_elements` `duplicate_elements` `move_elements` `resize_element` |
| Organize | `connect_elements` `add_label` `group_elements` `ungroup_elements` `align_elements` `distribute_elements` `resolve_overlaps` `reorder_elements` `lock_elements` `add_to_frame` |
| Export | `export_svg` `export_png` `export_library` `import_library` |
| Diagrams | `create_flowchart` |

Typical flow:

1. `create_scene`
2. `add_shape` / `add_text` / `create_flowchart`, then `connect_elements` to wire things up
3. `describe_scene` to verify
4. `save_scene` → open the `.excalidraw` file at excalidraw.com, and/or `export_svg` / `export_png` for a preview

Example — the whole auth flowchart above is one call:

```json
{
  "name": "create_flowchart",
  "arguments": {
    "nodes": [
      { "id": "start", "label": "Request", "shape": "ellipse", "backgroundColor": "#b2f2bb" },
      { "id": "auth", "label": "Authenticated?", "shape": "diamond", "backgroundColor": "#ffec99" },
      { "id": "handler", "label": "Route handler" },
      { "id": "reject", "label": "401 Unauthorized", "backgroundColor": "#ffc9c9" },
      { "id": "db", "label": "Database" }
    ],
    "edges": [
      { "from": "start", "to": "auth" },
      { "from": "auth", "to": "handler", "label": "yes" },
      { "from": "auth", "to": "reject", "label": "no", "strokeStyle": "dashed" },
      { "from": "handler", "to": "db", "label": "query" }
    ]
  }
}
```

## Notes

- Coordinates: y grows downward; shapes are positioned by their top-left corner.
- PNG export uses the optional `@resvg/resvg-js` dependency; SVG export has no native dependencies.
- Text sizing is estimated headlessly (~0.6em per character); Excalidraw re-measures precisely when a file is opened.

## Development

```bash
npm run build   # compile TypeScript
npm test        # end-to-end smoke test (spawns the server with a real MCP client)
```

The smoke test writes example output (`demo.excalidraw`, `flowchart.excalidraw`, SVG/PNG renders, a `.excalidrawlib`) into `examples/`.