Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Β 
Β 

Latest commit

Β 

History

74 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

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

Table of Contents

What It Is

This repo contains two separate processes:

  • Canvas server: web UI + REST API + WebSocket updates (default http://localhost: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 (26 tools)
State Stateless β€” each call is independent Persistent live canvas with real-time sync
Element CRUD No Full create / read / update / delete per element
AI sees the canvas No describe_scene (structured text) + get_canvas_screenshot (image)
Iterative refinement No β€” regenerate the whole diagram Draw β†’ look β†’ adjust β†’ look again, element by element
Layout tools No align_elements, distribute_elements, group / ungroup
File I/O No export_scene / import_scene (.excalidraw JSON)
Snapshot & rollback No snapshot_scene / restore_snapshot
Mermaid conversion No create_from_mermaid
Shareable URLs Yes Yes β€” export_to_excalidraw_url
Design guide read_me cheat sheet read_diagram_guide (colors, sizing, layout, anti-patterns)
Viewport control Camera animations set_viewport (zoom-to-fit, center on element, manual zoom)
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
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

v2.0 β€” Canvas Toolkit

  • 13 new MCP tools (26 total): get_element, clear_canvas, export_scene, import_scene, export_to_image, duplicate_elements, snapshot_scene, restore_snapshot, describe_scene, get_canvas_screenshot, read_diagram_guide, export_to_excalidraw_url, set_viewport
  • Closed feedback loop: AI can now inspect the canvas (describe_scene) and see it (get_canvas_screenshot returns an image) β€” enabling iterative refinement
  • Design guide: read_diagram_guide returns best-practice color palettes, sizing rules, layout patterns, and anti-patterns β€” dramatically improves AI-generated diagram quality
  • Shareable URLs: export_to_excalidraw_url encrypts and uploads the scene to excalidraw.com, returns a shareable link anyone can open
  • Viewport control: set_viewport with scrollToContent, scrollToElementId, or manual zoom/offset β€” agents can auto-fit diagrams after creation
  • File I/O: export/import full .excalidraw JSON files
  • Snapshots: save and restore named canvas states
  • Skill fallback: Agent skill auto-detects MCP vs REST API mode, gracefully falls back to HTTP endpoints when MCP server isn't configured
  • Fixed all previously known issues: align_elements / distribute_elements fully implemented, points type normalization, removed invalid label type, removed HTTP transport dead code, ungroup_elements now errors on failure

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

HOST=0.0.0.0 PORT=3000 npm run canvas

Open http://localhost:3000.

Terminal 2: run the MCP server (stdio)

EXPRESS_SERVER_URL=http://localhost: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://localhost:3000
ENABLE_CANVAS_SYNC Enable real-time canvas sync true

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://localhost: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://localhost: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://localhost: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://localhost: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://localhost: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://localhost:3000",
        "ENABLE_CANVAS_SYNC": "true"
      }
    }
  }
}

Canvas is optional: The MCP server works without the canvas in API-only mode (for programmatic access only).

πŸ› οΈ Environment Variables

Variable Default Description
EXPRESS_SERVER_URL http://localhost:3000 Canvas server URL for MCP sync
ENABLE_CANVAS_SYNC true Enable/disable canvas synchronization
LOG_FILE_PATH excalidraw.log Path to the log file
DEBUG false Enable debug logging
PORT 3000 Canvas server port
HOST localhost Canvas server host

πŸ“Š API Endpoints

The canvas server provides these REST endpoints:

Method Endpoint Description
GET /api/elements Get all elements
POST /api/elements Create new element
PUT /api/elements/:id Update element
DELETE /api/elements/:id Delete element
POST /api/elements/batch Create multiple elements
GET /health Server health check

🎨 MCP Tools Available

Element Management

  • create_element - Create any type of Excalidraw element
  • update_element - Modify existing elements
  • delete_element - Remove elements
  • query_elements - Search elements with filters

Batch Operations

  • batch_create_elements - Create complex diagrams in one call

Element Organization

  • group_elements - Group multiple elements
  • ungroup_elements - Ungroup element groups
  • align_elements - Align elements (left, center, right, top, middle, bottom)
  • distribute_elements - Distribute elements evenly
  • lock_elements / unlock_elements - Lock/unlock elements

Resource Access

  • get_resource - Access scene, library, theme, or elements data

Export & Download ✨ NEW!

  • export_canvas - Export canvas to PNG or SVG with light/dark theme support

🎨 Export Canvas Feature

The export feature allows you to download your Excalidraw canvas in PNG or SVG format with customizable theme options.

Using MCP Tool

// Export as PNG with light theme
{
  "format": "png",
  "theme": "light",
  "filename": "my-diagram"
}

// Export as SVG with dark theme
{
  "format": "svg",
  "theme": "dark",
  "filename": "my-dark-diagram"
}

Using Canvas UI

The canvas interface provides four quick export buttons:

  • πŸ“· PNG Light - Export as PNG with light background
  • πŸŒ™ PNG Dark - Export as PNG with dark background
  • πŸ“ SVG Light - Export as SVG with light background
  • πŸŒ‘ SVG Dark - Export as SVG with dark background

Export Options

Parameter Type Required Description
format 'png' | 'svg' Yes Export format
theme 'light' | 'dark' No Theme mode (default: 'light')
filename string No Custom filename without extension

Features

  • βœ… High-quality PNG exports (95% quality)
  • βœ… Vector SVG exports for scalability
  • βœ… Automatic dark/light theme switching
  • βœ… Custom background colors based on theme
  • βœ… Automatic file download in browser
  • βœ… Preserves all element properties and styles

πŸ—οΈ Development Architecture

Frontend (frontend/src/)

  • React + TypeScript: Modern TSX components with full type safety
  • Vite Build System: Fast development and optimized production builds
  • Official Excalidraw: @excalidraw/excalidraw package with TypeScript types
  • WebSocket Client: Type-safe real-time element synchronization
  • Clean UI: Production-ready interface with proper TypeScript typing

Canvas Server (src/server.ts β†’ dist/server.js)

  • TypeScript + Express.js: Fully typed REST API + static file serving
  • WebSocket: Type-safe real-time client communication
  • Element Storage: In-memory with comprehensive type definitions
  • CORS: Cross-origin support with proper typing

MCP Server (src/index.ts β†’ dist/index.js)

  • TypeScript MCP Protocol: Type-safe Model Context Protocol implementation
  • Canvas Sync: Strongly typed HTTP requests to canvas server
  • Element Management: Full CRUD operations with comprehensive type checking
  • Batch Support: Type-safe complex diagram creation

Type System (src/types.ts)

  • Excalidraw Element Types: Complete type definitions for all element types
  • API Response Types: Strongly typed REST API interfaces
  • WebSocket Message Types: Type-safe real-time communication
  • Server Element Types: Enhanced element types with metadata

πŸ› Troubleshooting

Canvas Not Loading

  • Ensure npm run build completed successfully
  • Check that dist/index.html and dist/frontend/ directory exist
  • Verify canvas server is running on port 3000
  • Check if port 3000 is already in use: lsof -i :3000 (macOS/Linux) or netstat -ano | findstr :3000 (Windows)

Elements Not Syncing

  • Confirm canvas server is running and accessible at http://localhost:3000
  • Check ENABLE_CANVAS_SYNC=true in MCP server environment configuration
  • Verify EXPRESS_SERVER_URL points to correct canvas server URL
  • Check browser console for WebSocket connection errors
  • For Docker: Ensure --network host flag is used

WebSocket Connection Issues

  • Check browser console for WebSocket errors (F12 β†’ Console tab)
  • Ensure no firewall blocking WebSocket connections on port 3000
  • Try refreshing the browser page
  • Verify canvas server is running: curl http://localhost:3000/health

Docker Issues

Canvas Container:

  • Check if container is running: docker ps | grep canvas
  • View logs: docker logs mcp-excalidraw-canvas
  • Ensure port 3000 is not already in use

MCP Container:

  • For Docker MCP server, ensure --network host is used (required to access localhost:3000)
  • Verify -i flag is present (required for MCP stdin/stdout protocol)
  • Check environment variables are properly set

Build Errors

  • Delete node_modules and dist/ directories, then run npm install && npm run build
  • Check Node.js version (requires 16+): node --version
  • Run npm run type-check to identify TypeScript issues
  • Verify dist/ directory contains both index.js, server.js, and frontend/ after build

NPM Package Issues

  • Status: NPM package is under development
  • Recommendation: Use local or Docker installation methods for production use

πŸ“‹ Project Structure

mcp_excalidraw/
β”œβ”€β”€ frontend/
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ App.tsx          # Main React component (TypeScript)
β”‚   β”‚   └── main.tsx         # React entry point (TypeScript)
β”‚   └── index.html           # HTML template
β”œβ”€β”€ src/ (TypeScript Source)
β”‚   β”œβ”€β”€ index.ts            # MCP server (TypeScript)
β”‚   β”œβ”€β”€ server.ts           # Canvas server (Express + WebSocket, TypeScript)
β”‚   β”œβ”€β”€ types.ts            # Comprehensive type definitions
β”‚   └── utils/
β”‚       └── logger.ts       # Logging utility (TypeScript)
β”œβ”€β”€ dist/ (Compiled Output)
β”‚   β”œβ”€β”€ index.js            # Compiled MCP server
β”‚   β”œβ”€β”€ server.js           # Compiled Canvas server
β”‚   β”œβ”€β”€ types.js            # Compiled type definitions
β”‚   β”œβ”€β”€ utils/
β”‚   β”‚   └── logger.js       # Compiled logging utility
β”‚   └── frontend/           # Built React frontend
β”œβ”€β”€ tsconfig.json          # TypeScript configuration
β”œβ”€β”€ vite.config.js         # Vite build configuration
β”œβ”€β”€ package.json           # Dependencies and scripts
└── README.md              # This file

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://localhost: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://localhost: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 (26 Total)

Category Tools
Element CRUD create_element, get_element, update_element, delete_element, query_elements, batch_create_elements, duplicate_elements
Layout align_elements, distribute_elements, group_elements, ungroup_elements, lock_elements, unlock_elements
Scene Awareness describe_scene, get_canvas_screenshot
File I/O export_scene, import_scene, export_to_image, export_to_excalidraw_url, create_from_mermaid
State Management clear_canvas, snapshot_scene, restore_snapshot
Viewport set_viewport
Design Guide read_diagram_guide
Resources get_resource

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

Testing

Canvas Smoke Test (HTTP)

curl http://localhost:3000/health

MCP Smoke Test (MCP Inspector)

List tools:

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

Create a rectangle:

npx @modelcontextprotocol/inspector --cli \
  -e EXPRESS_SERVER_URL=http://localhost:3000 \
  -e ENABLE_CANVAS_SYNC=true -- \
  node dist/index.js --method tools/call --tool-name create_element \
  --tool-arg type=rectangle --tool-arg x=100 --tool-arg y=100 \
  --tool-arg width=300 --tool-arg 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: Elements are stored in-memory β€” restarting the server clears everything. Use export_scene / snapshots as a workaround.
  • Image export requires a browser: export_to_image and get_canvas_screenshot rely on the frontend doing the actual rendering. The canvas UI must be open in a browser.

Contributions welcome!

Development

npm run type-check
npm run build

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages