Skip to main content
Glama

Excalidraw MCP Server & Agent Skill

CI Docker Build & Push NPM Version License

Run a live Excalidraw canvas and control it from AI agents. This repo provides:

  • MCP Server: Connect via Model Context Protocol (Claude Desktop, Cursor, Codex CLI, etc.)

  • Agent Skill: Portable skill for Claude Code, Codex CLI, and other skill-enabled agents

Keywords: Excalidraw agent skill, Excalidraw MCP server, AI diagramming, Claude Code skill, Codex CLI skill, Claude Desktop MCP, Cursor MCP, Mermaid to Excalidraw.

Demo

MCP Excalidraw Demo

AI agent creates a complete architecture diagram from a single prompt (4x speed). Watch full video on YouTube

Related MCP server: Excalidraw MCP Server

Table of Contents

What It Is

This repo contains two separate processes:

  • Canvas server: web UI + REST API + WebSocket updates (default http://127.0.0.1:3000)

  • MCP server: exposes MCP tools over stdio; syncs to the canvas via EXPRESS_SERVER_URL

How We Differ from the Official Excalidraw MCP

Excalidraw now has an official MCP — it's great for quick, prompt-to-diagram generation rendered inline in chat. We solve a different problem.

Official Excalidraw MCP

This Project

Approach

Prompt in, diagram out (one-shot)

Programmatic element-level control (6 focused tools)

State

Stateless — each call is independent

Persistent live canvas with real-time sync

Element CRUD

No

create / read / update / delete, batch-first, with id-based upsert

AI sees the canvas

No

read mode describe (structured text) + screenshot (headless image)

Iterative refinement

No — regenerate the whole diagram

Draw → look → adjust → look again, element by element

Layout tools

No

update arrange: align / distribute / group / ungroup / lock, plus deterministic auto-layout on create

Live-bound arrows

No

create from/to writes native Excalidraw bindings — arrows re-route when nodes move

File I/O

No

read mode export (.excalidraw JSON)

Snapshot & rollback

No

read mode snapshots (list / save / restore)

Mermaid conversion

No

create with a mermaid string

Design guide

read_me cheat sheet

read mode guide (colors, sizing, layout, anti-patterns)

Live canvas UI

Rendered inline in chat

Standalone Excalidraw app synced via WebSocket

Multi-agent

Single user

Multiple agents can draw on the same canvas concurrently

Browser collaboration

Hosted app only

Cross-tab scene sync plus native Excalidraw collaborator cursors

Works without MCP

No

Yes — REST API fallback via agent skill

TL;DR — The official MCP generates diagrams. We give AI agents a full canvas toolkit to build, inspect, and iteratively refine diagrams — including the ability to see what they drew.

What's New

v3.0 — Six-Tool Rebuild

  • Collapsed to 6 tools: set_room, create, update, delete, read, screenshot. Everything the old ~28-tool surface did now lives under these (e.g. align/distribute/group/lock → update.arrange; export/snapshots/describe/guide → read modes; screenshot/image export → screenshot).

  • Deterministic upsert + auto-layout: reuse an element id to create-or-update in place; omit x/y and nodes are auto-placed with no randomness (layered when from/to edges connect them, else a grid — same input, same coordinates).

  • Declarative live-bound arrows: give an arrow/line from/to = a node id and the server both routes the endpoints and writes native Excalidraw startBinding/endBinding + boundElements, so the arrow stays attached and re-routes when the node is dragged in the browser.

  • Headless screenshots: screenshot renders via a sidecar — no browser tab required — with bbox / scale / maxDim framing.

  • Single source of truth: this repo is now the one MCP; the npx stdio install points here, and the heavy frontend-only deps moved to devDependencies to keep that install fast.

v2.0 — Canvas Toolkit

  • Closed feedback loop: AI can inspect the canvas (read mode describe) and see it (screenshot returns an image) — enabling iterative refinement

  • Design guide: read mode guide returns best-practice color palettes, sizing rules, layout patterns, and anti-patterns — dramatically improves AI-generated diagram quality

  • File I/O: export full .excalidraw JSON (read mode export)

  • Snapshots: save and restore named canvas states (read mode snapshots)

  • Skill fallback: Agent skill auto-detects MCP vs REST API mode, gracefully falls back to HTTP endpoints when MCP server isn't configured

  • Browser collaboration: ordinary edits use low-latency delta sync between tabs, full-scene imports still use safe whole-scene sync, and websocket pointer updates drive native Excalidraw collaborator cursors

v1.x

  • Agent skill: skills/excalidraw-skill/ (portable instructions + helper scripts for export/import and repeatable CRUD)

  • Better testing loop: MCP Inspector CLI examples + browser screenshot checks (agent-browser)

  • Bugfixes: batch create now preserves element ids (fixes update/delete after batch); frontend entrypoint fixed (main.tsx)

Quick Start (Local)

Prereqs: Node >= 18, npm

npm ci
npm run build

Terminal 1: start the canvas

PORT=3000 npm run canvas

Security note: The server defaults to binding on 127.0.0.1 only. If you need to expose it on a network interface (e.g. Docker, remote access), set HOST=0.0.0.0 — but ensure you have network-level access controls in place, as the API has no built-in authentication.

Open http://127.0.0.1:3000.

Terminal 2: run the MCP server (stdio)

EXPRESS_SERVER_URL=http://127.0.0.1:3000 node dist/index.js

Quick Start (Docker)

Canvas server:

docker run -d -p 3000:3000 --name mcp-excalidraw-canvas ghcr.io/yctimlin/mcp_excalidraw-canvas:latest

MCP server (stdio) is typically launched by your MCP client (Claude Desktop/Cursor/etc.). If you want a local container for it, use the image ghcr.io/yctimlin/mcp_excalidraw:latest and set EXPRESS_SERVER_URL to point at the canvas.

Configure MCP Clients

The MCP server runs over stdio and can be configured with any MCP-compatible client. Below are configurations for both local (requires cloning and building) and Docker (pull-and-run) setups.

Environment Variables

Variable

Description

Default

EXPRESS_SERVER_URL

URL of the canvas server

http://127.0.0.1:3000

ROOM_ID

Optional fallback room id. Omit it for arbitrary-room workflows and use set_room, roomUrl, or roomId per tool call instead.

unset

ENABLE_CANVAS_SYNC

Enable real-time canvas sync

true

MCP_AGENT_CURSOR

Show MCP tool activity as a collaborator cursor when canvas sync is enabled

true

MCP_AGENT_NAME

Collaborator label for MCP agent cursor presence

MCP Agent

MCP_AGENT_COLOR

Cursor color, either a stroke hex color or JSON with background/stroke

#1971c2 stroke

Room Targeting

The MCP server can work with arbitrary Zephy rooms without reinstalling the MCP server.

  • Call set_room with a pasted room URL, such as https://draw.proklov.dev/r/<roomId>, to make that room active for later tool calls.

  • Or pass roomUrl / roomId directly to any canvas tool for a one-off operation.

  • ROOM_ID remains supported only as a fallback default for single-room installs.

Reading Large Boards

read mode describe is bounded by default so large canvases do not flood the model context. The default overview returns a summary, spatial section index, and prominent text. Page into the board with focused calls (pass these args to the read tool):

{ "mode": "describe", "detail": "overview" }
{ "mode": "describe", "detail": "elements", "sectionIndex": 2, "limit": 60 }
{ "mode": "describe", "detail": "elements", "types": ["text"], "textIncludes": "SESSION" }
{ "mode": "describe", "detail": "connections", "sectionIndex": 4 }
{ "mode": "describe", "detail": "overview", "filePath": "/tmp/board-overview.md" }
{ "mode": "describe", "detail": "full" }

Use detail: "full" only when you truly need the complete dump. read mode query also accepts filePath to write results to disk instead of returning a large inline payload. screenshot renders headlessly via the renderer sidecar — no browser tab required.


Claude Desktop

Config location:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

  • Windows: %APPDATA%\Claude\claude_desktop_config.json

  • Linux: ~/.config/Claude/claude_desktop_config.json

Local (node)

{
  "mcpServers": {
    "excalidraw": {
      "command": "node",
      "args": ["/absolute/path/to/mcp_excalidraw/dist/index.js"],
      "env": {
        "EXPRESS_SERVER_URL": "http://127.0.0.1:3000",
        "ENABLE_CANVAS_SYNC": "true"
      }
    }
  }
}

Docker

{
  "mcpServers": {
    "excalidraw": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-e", "EXPRESS_SERVER_URL=http://host.docker.internal:3000",
        "-e", "ENABLE_CANVAS_SYNC=true",
        "ghcr.io/yctimlin/mcp_excalidraw:latest"
      ]
    }
  }
}

Claude Code

Use the claude mcp add command to register the MCP server.

Local (node) - User-level (available across all projects):

claude mcp add excalidraw --scope user \
  -e EXPRESS_SERVER_URL=http://127.0.0.1:3000 \
  -e ENABLE_CANVAS_SYNC=true \
  -- node /absolute/path/to/mcp_excalidraw/dist/index.js

Local (node) - Project-level (shared via .mcp.json):

claude mcp add excalidraw --scope project \
  -e EXPRESS_SERVER_URL=http://127.0.0.1:3000 \
  -e ENABLE_CANVAS_SYNC=true \
  -- node /absolute/path/to/mcp_excalidraw/dist/index.js

Docker

claude mcp add excalidraw --scope user \
  -- docker run -i --rm \
  -e EXPRESS_SERVER_URL=http://host.docker.internal:3000 \
  -e ENABLE_CANVAS_SYNC=true \
  ghcr.io/yctimlin/mcp_excalidraw:latest

Manage servers:

claude mcp list              # List configured servers
claude mcp remove excalidraw # Remove a server

Cursor

Config location: .cursor/mcp.json in your project root (or ~/.cursor/mcp.json for global config)

Local (node)

{
  "mcpServers": {
    "excalidraw": {
      "command": "node",
      "args": ["/absolute/path/to/mcp_excalidraw/dist/index.js"],
      "env": {
        "EXPRESS_SERVER_URL": "http://127.0.0.1:3000",
        "ENABLE_CANVAS_SYNC": "true"
      }
    }
  }
}

Docker

{
  "mcpServers": {
    "excalidraw": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-e", "EXPRESS_SERVER_URL=http://host.docker.internal:3000",
        "-e", "ENABLE_CANVAS_SYNC=true",
        "ghcr.io/yctimlin/mcp_excalidraw:latest"
      ]
    }
  }
}

Codex CLI

Use the codex mcp add command to register the MCP server.

Local (node)

codex mcp add excalidraw \
  --env EXPRESS_SERVER_URL=http://127.0.0.1:3000 \
  --env ENABLE_CANVAS_SYNC=true \
  -- node /absolute/path/to/mcp_excalidraw/dist/index.js

Docker

codex mcp add excalidraw \
  -- docker run -i --rm \
  -e EXPRESS_SERVER_URL=http://host.docker.internal:3000 \
  -e ENABLE_CANVAS_SYNC=true \
  ghcr.io/yctimlin/mcp_excalidraw:latest

Manage servers:

codex mcp list              # List configured servers
codex mcp remove excalidraw # Remove a server

OpenCode

Config location: ~/.config/opencode/opencode.json or project-level opencode.json

Local (node)

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "excalidraw": {
      "type": "local",
      "command": ["node", "/absolute/path/to/mcp_excalidraw/dist/index.js"],
      "enabled": true,
      "environment": {
        "EXPRESS_SERVER_URL": "http://127.0.0.1:3000",
        "ENABLE_CANVAS_SYNC": "true"
      }
    }
  }
}

Docker

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "excalidraw": {
      "type": "local",
      "command": ["docker", "run", "-i", "--rm", "-e", "EXPRESS_SERVER_URL=http://host.docker.internal:3000", "-e", "ENABLE_CANVAS_SYNC=true", "ghcr.io/yctimlin/mcp_excalidraw:latest"],
      "enabled": true
    }
  }
}

Antigravity (Google)

Config location: ~/.gemini/antigravity/mcp_config.json

Local (node)

{
  "mcpServers": {
    "excalidraw": {
      "command": "node",
      "args": ["/absolute/path/to/mcp_excalidraw/dist/index.js"],
      "env": {
        "EXPRESS_SERVER_URL": "http://127.0.0.1:3000",
        "ENABLE_CANVAS_SYNC": "true"
      }
    }
  }
}

Docker

{
  "mcpServers": {
    "excalidraw": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-e", "EXPRESS_SERVER_URL=http://host.docker.internal:3000",
        "-e", "ENABLE_CANVAS_SYNC=true",
        "ghcr.io/yctimlin/mcp_excalidraw:latest"
      ]
    }
  }
}

Notes

  • Docker networking: Use host.docker.internal to reach the canvas server running on your host machine. On Linux, you may need --add-host=host.docker.internal:host-gateway or use 172.17.0.1.

  • Canvas server: Must be running before the MCP server connects. Start it with npm run canvas (local) or docker run -d -p 3000:3000 ghcr.io/yctimlin/mcp_excalidraw-canvas:latest (Docker).

  • Absolute paths: When using local node setup, replace /absolute/path/to/mcp_excalidraw with the actual path where you cloned and built the repo.

  • In-memory storage: The canvas server stores elements in memory. Restarting the server will clear all elements. Use the export/import scripts if you need persistence.

Agent Skill (Optional)

This repo includes a skill at skills/excalidraw-skill/ that provides:

  • Workflow playbook (SKILL.md): step-by-step guidance for drawing, refining, and exporting diagrams

  • Cheatsheet (references/cheatsheet.md): MCP tool and REST API reference

  • Helper scripts (scripts/*.cjs): export, import, clear, healthcheck, CRUD operations

The skill complements the MCP server by giving your AI agent structured workflows to follow.

Install The Skill (Codex CLI example)

mkdir -p ~/.codex/skills
cp -R skills/excalidraw-skill ~/.codex/skills/excalidraw-skill

To update an existing installation, remove the old folder first (rm -rf ~/.codex/skills/excalidraw-skill) then re-copy.

Install The Skill (Claude Code)

User-level (available across all your projects):

mkdir -p ~/.claude/skills
cp -R skills/excalidraw-skill ~/.claude/skills/excalidraw-skill

Project-level (scoped to a specific project, can be committed to the repo):

mkdir -p /path/to/your/project/.claude/skills
cp -R skills/excalidraw-skill /path/to/your/project/.claude/skills/excalidraw-skill

Then invoke the skill in Claude Code with /excalidraw-skill.

To update an existing installation, remove the old folder first then re-copy.

Use The Skill Scripts

All scripts respect EXPRESS_SERVER_URL (default http://127.0.0.1:3000) or accept --url.

EXPRESS_SERVER_URL=http://127.0.0.1:3000 node skills/excalidraw-skill/scripts/healthcheck.cjs
EXPRESS_SERVER_URL=http://127.0.0.1:3000 node skills/excalidraw-skill/scripts/export-elements.cjs --out diagram.elements.json
EXPRESS_SERVER_URL=http://127.0.0.1:3000 node skills/excalidraw-skill/scripts/import-elements.cjs --in diagram.elements.json --mode batch

When The Skill Is Useful

  • Repository workflow: export elements as JSON, commit it, and re-import later.

  • Reliable refactors: clear + re-import in sync mode to make canvas match a file.

  • Automated smoke tests: create/update/delete a known element to validate a deployment.

  • Repeatable diagrams: keep a library of element JSON snippets and import them.

See skills/excalidraw-skill/SKILL.md and skills/excalidraw-skill/references/cheatsheet.md.

MCP Tools (6 Total)

The surface is deliberately small: six powerful, batch-first, deterministic tools. Reuse an element id to upsert (create-or-update); the same input always produces the same auto-layout coordinates.

Tool

What it does

set_room

Pin/switch the active room (full roomUrl, or roomId+expressUrl); call with no args to report the current room. Any tool also accepts a per-call roomUrl/roomId override.

create

Create/upsert one or many elements (elements: [...] or a single inline element). Connect nodes with from/to = element id — the server routes endpoints and writes native Excalidraw bindings so arrows follow nodes when moved. Omit x/y for deterministic auto-layout (layered when edges connect nodes, else a grid). Also does mermaid rendering and copyOf duplication.

update

Select by id, ids, or query (type/filter/bbox), then either apply a set of properties or run an arrange op: align / distribute / group / ungroup / lock / unlock.

delete

Remove by id, ids, or query, or all: true to clear the canvas.

read

One reader with mode: describe (bounded overview + section index), query, get, export (.excalidraw JSON), snapshots (list / save / restore), guide (diagram design guide).

screenshot

Headless PNG/SVG via the renderer sidecar (no browser tab needed). Frame with bbox / scale / maxDim; returns the image inline or to filePath.

Full schemas are discoverable via tools/list or in skills/excalidraw-skill/references/cheatsheet.md.

Testing

Canvas Smoke Test (HTTP)

curl http://127.0.0.1:3000/health

Local Bind Regression Test

npm run test:bind

Realtime WebSocket Regression Test

npm run test:realtime

MCP Smoke Test (MCP Inspector)

List tools:

npx @modelcontextprotocol/inspector --cli \
  -e EXPRESS_SERVER_URL=http://127.0.0.1:3000 \
  -e ENABLE_CANVAS_SYNC=true -- \
  node dist/index.js --method tools/list

Create a rectangle (the create tool is batch-first — pass an elements array):

npx @modelcontextprotocol/inspector --cli \
  -e EXPRESS_SERVER_URL=http://127.0.0.1:3000 \
  -e ENABLE_CANVAS_SYNC=true -- \
  node dist/index.js --method tools/call --tool-name create \
  --tool-arg 'elements=[{"type":"rectangle","x":100,"y":100,"width":300,"height":200}]'

Frontend Screenshots (agent-browser)

If you use agent-browser for UI checks:

agent-browser install
agent-browser open http://127.0.0.1:3000
agent-browser wait --load networkidle
agent-browser screenshot /tmp/canvas.png

Troubleshooting

  • Canvas not updating: confirm EXPRESS_SERVER_URL points at the running canvas server.

  • Updates/deletes fail after batch creation: ensure you are on a build that includes the batch id preservation fix (merged via PR #34).

Known Issues / TODO

All previously listed bugs have been fixed in v2.0. Remaining items:

  • Persistent storage: rooms are checkpointed to disk (with a write-ahead log), but for portable backups use read mode export / snapshots.

Contributions welcome!

Development

npm run type-check
npm run build

Maintenance

ActivityStale
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    F
    maintenance
    Enables AI agents to programmatically control a live Excalidraw canvas through element-level CRUD operations and real-time synchronization. It allows agents to iteratively build, inspect, and refine diagrams while providing visual feedback via screenshots and scene descriptions.
    1,611
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI agents to programmatically control a live Excalidraw canvas with element-level CRUD operations and real-time synchronization. It supports iterative diagramming through scene descriptions, screenshots, and advanced layout tools for collaborative AI-human workflows.
    1,611
    2
    MIT