Unofficial MCP server for Excalidraw diagram management with canvas sync
SaferSkills independently audited excalidraw-mcp (MCP Server) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
🙏 Acknowledgments This project is based on and extends the excellent work from yctimlin/mcp_excalidraw. Special thanks to the original contributors for creating the foundation that made this enhanced version possible.
A dual-language MCP server that combines Excalidraw canvas manipulation with AI-driven tool access for live diagram creation.
It uses a Python FastMCP server plus a TypeScript canvas server for separation of protocol handling, canvas state, and browser updates.
Crackerjack is used as the standard quality-control and CI/CD gate for the Python side of this repo. Pair it with the existing TypeScript build and test checks for cross-stack changes.
See MCP Excalidraw in Action!
Watch how AI agents create and manipulate diagrams in real-time on the live canvas
sequenceDiagram
participant AI as AI Agent<br/>(Claude)
participant MCP as MCP Server<br/>(Python FastMCP)
participant Canvas as Canvas Server<br/>(Express.js)
participant WS as WebSocket Server
participant UI as React Frontend<br/>(Excalidraw)
AI->>MCP: MCP Tool Call<br/>(create_element)
activate MCP
MCP->>MCP: Validate Request<br/>(Pydantic)
MCP->>Canvas: HTTP POST<br/>/api/elements
activate Canvas
Canvas->>Canvas: Store Element<br/>(in-memory Map)
Canvas->>WS: Broadcast Update
WS->>UI: WebSocket Message<br/>(element_created)
deactivate Canvas
UI->>UI: Render in Excalidraw
MCP-->>AI: Tool Response
deactivate MCP
Note over MCP,Canvas: Auto-management: Python server<br/>monitors and restarts canvas server
Note over WS,UI: Real-time: All connected clients<br/>receive updates simultaneouslyHybrid Architecture Benefits:
#### 1. Clone and Setup
git clone https://github.com/lesleslie/excalidraw-mcp.git
cd excalidraw-mcp
# Install Python dependencies
uv sync
# Install Node.js dependencies from package-lock.json (node_modules not in repo)
npm install
npm run build#### 2. Start the System
# The Python MCP server auto-starts the canvas server
uv run python excalidraw_mcp/server.py
# Or manually start canvas server (optional)
npm run canvas#### 3. Access the Canvas
Open your browser and navigate to:
http://localhost:3031# Development mode (TypeScript watch + Vite dev server)
npm run dev
# Or production mode
npm run productionDevelopment Workflow:
uv sync && npm install && npm run buildnpm run dev (TypeScript watch + Vite dev server)pytest (Python) + npm test (TypeScript)uv run ruff check + npm run type-checkDevelopment Modes:
| Mode | Command | Use Case |
|---|---|---|
| Dev | npm run dev | Active development with hot-reload |
| Build | npm run build | Compile TypeScript + React |
| Canvas | npm run canvas | Start canvas server only |
| Production | npm run production | Full build + start |
| Script | Description |
|---|---|
npm start | Build and start MCP server (dist/index.js) |
npm run canvas | Build and start canvas server (dist/server.js) |
npm run canvas-bg | Build and start canvas server in background |
npm run start-canvas | Build and start canvas server |
npm run canvas-for-npx | Special script for npx usage |
npm run start-all | Start both servers together |
npm run build | Build both frontend and TypeScript backend |
npm run build:frontend | Build React frontend only |
npm run build:server | Compile TypeScript backend to JavaScript |
npm run build:types | Generate TypeScript declaration files only |
npm run dev | Start TypeScript watch mode + Vite dev server |
npm run dev:server | Start TypeScript in watch mode only |
npm run type-check | Run TypeScript type checking without compilation |
npm run production | Build + start in production mode |
npm test | Run all tests |
npm run test:watch | Run tests in watch mode |
npm run test:coverage | Run tests with coverage report |
npm run test:unit | Run unit tests only |
npm run test:integration | Run integration tests only |
http://localhost:3031The MCP server provides these tools for creating visual diagrams:
#### Basic Element Creation
// Create a rectangle
{
"type": "rectangle",
"x": 100,
"y": 100,
"width": 200,
"height": 100,
"backgroundColor": "#e3f2fd",
"strokeColor": "#1976d2",
"strokeWidth": 2
}#### Create Text Elements
{
"type": "text",
"x": 150,
"y": 125,
"text": "Process Step",
"fontSize": 16,
"strokeColor": "#333333"
}#### Create Arrows & Lines
{
"type": "arrow",
"x": 300,
"y": 130,
"width": 100,
"height": 0,
"strokeColor": "#666666",
"strokeWidth": 2
}#### Batch Creation for Complex Diagrams
{
"elements": [
{
"type": "rectangle",
"x": 100,
"y": 100,
"width": 120,
"height": 60,
"backgroundColor": "#fff3e0",
"strokeColor": "#ff9800"
},
{
"type": "text",
"x": 130,
"y": 125,
"text": "Start",
"fontSize": 16
}
]
}Add this configuration to your Claude Code .mcp.json:
{
"mcpServers": {
"excalidraw": {
"command": "uvx",
"args": ["excalidraw-mcp"],
"env": {
"EXPRESS_SERVER_URL": "http://localhost:3031",
"ENABLE_CANVAS_SYNC": "true"
}
}
}
}For local development, use:
{
"mcpServers": {
"excalidraw": {
"command": "uv",
"args": ["run", "python", "excalidraw_mcp/server.py"],
"cwd": "/absolute/path/to/excalidraw-mcp"
}
}
}Important: Replace /absolute/path/to/excalidraw-mcp with the actual absolute path to your cloned repository.
Add to your .cursor/mcp.json:
{
"mcpServers": {
"excalidraw": {
"command": "uvx",
"args": ["excalidraw-mcp"],
"env": {
"EXPRESS_SERVER_URL": "http://localhost:3031"
}
}
}
}For VS Code MCP extension, add to your settings:
{
"mcp": {
"servers": {
"excalidraw": {
"command": "uvx",
"args": ["excalidraw-mcp"],
"env": {
"EXPRESS_SERVER_URL": "http://localhost:3031"
}
}
}
}
}| Variable | Default | Description |
|---|---|---|
EXPRESS_SERVER_URL | http://localhost:3031 | Canvas server URL for MCP sync |
ENABLE_CANVAS_SYNC | true | Enable/disable canvas synchronization |
CANVAS_AUTO_START | true | Auto-start canvas server with MCP server |
SYNC_RETRY_ATTEMPTS | 3 | Number of retry attempts for failed operations |
SYNC_RETRY_DELAY_SECONDS | 1.0 | Base delay between retry attempts (seconds) |
SYNC_RETRY_MAX_DELAY_SECONDS | 30.0 | Maximum delay between retry attempts (seconds) |
SYNC_RETRY_EXPONENTIAL_BASE | 2.0 | Exponential base for backoff calculation |
SYNC_RETRY_JITTER | true | Enable/disable jitter for retry delays |
PORT | 3031 | Canvas server port |
HOST | localhost | Canvas server host |
DEBUG | false | Enable debug logging |
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 |
create_element - Create any type of Excalidraw elementupdate_element - Modify existing elementsdelete_element - Remove elementsquery_elements - Search elements with filtersbatch_create_elements - Create complex diagrams in one callgroup_elements - Group multiple elementsungroup_elements - Ungroup element groupsalign_elements - Align elements (left, center, right, top, middle, bottom)distribute_elements - Distribute elements evenlylock_elements / unlock_elements - Lock/unlock elementsget_resource - Access scene, library, theme, or elements datafrontend/src/)@excalidraw/excalidraw package with TypeScript typessrc/server.ts → dist/server.js)excalidraw_mcp/server.py)src/types.ts)flowchart TD
Start[Issue Detected] --> IssueType{What's the problem?}
IssueType -->|Canvas Not Loading| CanvasCheck{Build succeeded?}
IssueType -->|Elements Not Syncing| SyncCheck{Canvas server<br/>running?}
IssueType -->|WebSocket Issues| WSVerify{Check console<br/>for errors}
IssueType -->|Build Errors| BuildClean{Node version<br/>OK?}
IssueType -->|Python Errors| DepCheck{uv sync<br/>succeeded?}
CanvasCheck -->|No| A1[Run npm run build]
CanvasCheck -->|Yes| A2{Server running?}
A2 -->|No| A3[Check port 3031<br/>lsof -i :3031]
A2 -->|Yes| A4{Health check OK?}
A4 -->|No| A5[Review console logs]
A4 -->|Yes| A6[Check firewall]
SyncCheck -->|No| B1[Python auto-starts<br/>canvas server]
SyncCheck -->|Yes| B2{ENABLE_CANVAS_SYNC<br/>= true?}
B2 -->|No| B3[Set env variable]
B2 -->|Yes| B4{/health OK?}
B4 -->|No| B5[Check canvas<br/>server logs]
B4 -->|Yes| B6[Verify WebSocket<br/>connection]
WSVerify -->|Errors found| C1[Check firewall<br/>settings]
WSVerify -->|No errors| C2[Refresh browser<br/>page]
BuildClean -->|No| D1[Delete node_modules<br/>npm install]
BuildClean -->|Yes| D2[Run type-check<br/>npm run type-check]
DepCheck -->|No| E1[Run uv sync]
DepCheck -->|Yes| E2{Python 3.13+?}
E2 -->|No| E3[Install Python 3.13]
E2 -->|Yes| E4[Check uv<br/>installation]
style Start fill:#e3f2fd
style A1 fill:#c8e6c9
style A6 fill:#ffcdd2
style B1 fill:#c8e6c9
style E4 fill:#fff9c4npm run build completed successfullyENABLE_CANVAS_SYNC=true in environmenthttp://localhost:3031/healthnode_modules and run npm installnpm run type-check to identify TypeScript issuesuv sync to update Python dependenciesuv sync to install/update Python dependenciesuv --version to verify uv installationexcalidraw-mcp/
├── examples/ # Usage examples
├── excalidraw_mcp/ # Python FastMCP server
│ ├── monitoring/ # Monitoring and health check utilities
│ ├── server.py # Main MCP server (Python)
│ ├── config.py # Configuration management
│ ├── element_factory.py # Element creation utilities
│ ├── http_client.py # HTTP client for canvas server
│ ├── process_manager.py # Canvas server lifecycle management
│ ├── retry_utils.py # Retry mechanisms for failed operations
│ ├── cli.py # Command-line interface
│ ├── mcp_tools.py # MCP tool implementations
│ ├── __init__.py # Package initialization
│ └── __main__.py # Main entry point
├── frontend/ # React frontend
│ ├── src/
│ │ ├── App.tsx # Main React component (TypeScript)
│ │ └── main.tsx # React entry point (TypeScript)
│ └── index.html # HTML template
├── src/ # TypeScript canvas server
│ ├── middleware/ # Express middleware components
│ ├── storage/ # Element storage implementations
│ ├── utils/ # Utility functions
│ ├── websocket/ # WebSocket server components
│ ├── config.ts # Server configuration
│ ├── server.ts # Express server + WebSocket (TypeScript)
│ └── types.ts # Type definitions
├── dist/ # Compiled TypeScript output
│ ├── server.js # Compiled canvas server
│ ├── server.d.ts # Server type definitions
│ ├── server.js.map # Server source maps
│ ├── types.js # Compiled type definitions
│ ├── types.d.ts # Type definition files
│ ├── types.js.map # Type definition source maps
│ ├── utils/ # Compiled utilities
│ ├── assets/ # Frontend assets
│ └── frontend/ # Built React frontend
├── tests/ # Python test suite
│ ├── unit/ # Unit tests
│ ├── integration/ # Integration tests
│ ├── security/ # Security tests
│ ├── performance/ # Performance tests
│ └── e2e/ # End-to-end tests
├── .github/ # GitHub configurations
├── pyproject.toml # Python project configuration
├── package.json # Node.js dependencies and scripts
├── tsconfig.json # TypeScript configuration
└── README.md # This fileThis project uses consistent naming across different contexts:
excalidraw_mcp (underscore) - used in imports and Python module referencesexcalidraw-mcp (hyphen) - used for uvx excalidraw-mcp and pip installationexcalidraw-mcp (hyphen) - used for Node.js dependenciesexcalidraw - used in .mcp.json configurationExample Usage:
# Python imports (underscore)
from excalidraw_mcp.server import main
# Shell commands (hyphen)
uvx excalidraw-mcp
pip install excalidraw-mcp# Python tests with coverage
pytest --cov=excalidraw_mcp --cov-report=html
pytest --cov=excalidraw_mcp --cov-report=term-missing
# TypeScript tests with coverage
npm run test:coverage
# Run all tests
pytest && npm test
# Specific test categories
pytest tests/unit/ # Python unit tests
pytest tests/integration/ # Python integration tests
pytest -m security # Security tests
pytest -m performance # Performance benchmarks
npm run test:unit # TypeScript unit tests
npm run test:integration # TypeScript integration testsThis project enforces strict quality standards:
The Python package is published to PyPI as excalidraw-mcp:
# Install from PyPI
pip install excalidraw-mcp
# Use with uvx (recommended)
uvx excalidraw-mcpFor local development and testing:
# Install in editable mode
pip install -e .
# Or use UV for development
uv sync
uv run python excalidraw_mcp/server.pypyproject.toml and package.jsonWe welcome contributions! Please:
git checkout -b feature/amazing-feature)git commit -m 'Add amazing feature')git push origin feature/amazing-feature)This project is licensed under the MIT License - see the LICENSE file for details.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.