Install
$ agentstack add mcp-whallysson-excalidraw-mcp ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Excalidraw MCP Server
[](https://opensource.org/licenses/MIT) [](https://nodejs.org/) [](https://www.typescriptlang.org/) [](https://github.com/whallysson/excalidraw-mcp)
A Model Context Protocol (MCP) server that exposes Excalidraw diagram capabilities through standardized tools and resources, combined with a standalone React frontend for visual editing.
Features
- 🎨 MCP Protocol Integration: Control Excalidraw programmatically via AI assistants
- 🖥️ Standalone Frontend: Use Excalidraw interface independently
- 🔄 Real-Time Sync: WebSocket synchronization between frontend and MCP server
- 🐳 Docker Support: Run locally or via Docker Compose
- 📦 TypeScript: Fully typed codebase with Zod validation
- 🧪 Well Tested: Unit, integration, and E2E test coverage
Quick Start
Prerequisites
- Node.js 18+ (LTS recommended)
- Docker & Docker Compose (optional, for container deployment)
Local Development
Option 1: Start Everything with ONE Command (Recommended)
# Install dependencies (first time only)
npm install
cd backend && npm install
cd ../frontend && npm install
cd ..
# Configure environment (first time only)
cp backend/.env.example backend/.env
cp frontend/.env.example frontend/.env
# Start EVERYTHING (MCP + HTTP/WebSocket + Frontend)
npm run dev:all
This single command starts:
[MCP]- MCP Server (stdio) on backend[HTTP]- HTTP/WebSocket Server on port 3333[FRONTEND]- Frontend Vite dev server on port 5173
Open your browser at http://localhost:5173 and start creating diagrams!
Option 2: Start Services Separately (for debugging)
# Terminal 1: Backend MCP + HTTP/WebSocket Server
cd backend
npm run dev:all
# Terminal 2: Frontend
cd frontend
npm run dev
Option 3: Individual Processes (advanced)
# Terminal 1: HTTP/WebSocket Server only
cd backend && npm run dev
# Terminal 2: MCP Server only (for Claude Desktop integration)
cd backend && npm run dev:mcp
# Terminal 3: Frontend
cd frontend && npm run dev
Docker Deployment (Production)
IMPORTANT: Docker starts only the Frontend + HTTP/WebSocket Server. The MCP Server (stdio) must run locally for communication with Claude Desktop.
Single Container
Docker now uses 1 container that combines:
- ✅ Frontend (React/Vite static build)
- ✅ Backend HTTP Server (Express + WebSocket)
- ❌ MCP Server stdio (runs locally - see below)
Docker Commands
# Start application (Frontend + HTTP/WebSocket)
docker-compose up -d
# View logs
docker-compose logs -f
# Rebuild after changes
docker-compose down
docker-compose build
docker-compose up -d
# Stop application
docker-compose down
# Clean volumes (deletes canvas data)
docker-compose down -v
Access Application
- Frontend: http://localhost:3333
- Health Check: http://localhost:3333/health
- API: http://localhost:3333/api/canvas/main
MCP Server (Run Locally)
The MCP Server uses stdio protocol (stdin/stdout) and CANNOT run in Docker. Run it locally:
# Separate terminal: MCP Server for Claude Desktop
cd backend
npm run dev:mcp
Claude Desktop Configuration (claude_desktop_config.json):
{
"mcpServers": {
"excalidraw": {
"command": "npx",
"args": ["tsx", "/absolute/path/backend/src/index.ts"],
"env": {
"HTTP_SERVER_URL": "http://localhost:3333"
}
}
}
}
Complete Architecture
┌─────────────────────────────────────────┐
│ Docker Container (excalidraw-mcp) │
│ │
│ ┌──────────────┐ ┌────────────────┐ │
│ │ Frontend │ │ HTTP Server │ │
│ │ (Static Files)│◄──┤ Express + WS │ │
│ └──────────────┘ └────────────────┘ │
│ │
│ Port: 3333 │
└─────────────────────────────────────────┘
▲
│ HTTP POST /api/canvas/*/broadcast
│
┌─────────────────┴───────────────────────┐
│ Local Process (MCP Server) │
│ │
│ ┌──────────────────────────────────┐ │
│ │ MCP Server (stdio) │ │
│ │ JSON-RPC 2.0 Protocol │ │
│ └──────────────────────────────────┘ │
│ ▲ │
│ │ stdin/stdout │
│ │ │
│ ┌───────────────┴──────────────────┐ │
│ │ Claude Desktop (MCP Client) │ │
│ └──────────────────────────────────┘ │
└─────────────────────────────────────────┘
Complete Tests
Run automated tests:
# Test Docker (Frontend, HTTP, API, Health)
./test-complete-flow.sh
# View detailed results
cat DOCKER_TEST_RESULTS.md
Project Structure
├── backend/ # MCP server
│ ├── src/
│ │ ├── mcp/ # MCP tools and resources
│ │ ├── services/ # Canvas management, WebSocket, storage
│ │ ├── types/ # TypeScript definitions
│ │ └── utils/ # Logger, validation helpers
│ └── tests/ # Unit and integration tests
├── frontend/ # React frontend
│ ├── src/
│ │ ├── hooks/ # WebSocket client
│ │ ├── services/ # API client
│ │ └── utils/ # Element validation, conversion
│ └── tests/ # E2E tests
└── docker-compose.yml # Orchestration
Installation
Backend Dependencies
cd backend
npm install
Frontend Dependencies
cd frontend
npm install
Local Setup
Step 1: Install Dependencies
Install dependencies for both backend and frontend:
# Backend
cd backend
npm install
# Frontend
cd ../frontend
npm install
Step 2: Configure Environment Variables
Copy the example environment files and configure them:
# Backend environment
cp backend/.env.example backend/.env
# Frontend environment
cp frontend/.env.example frontend/.env
Backend .env configuration:
PORT=3333
WS_PORT=3333
NODE_ENV=development
LOG_LEVEL=debug
CANVAS_DATA_DIR=./data
SERVER_NAME=excalidraw-mcp-server
SERVER_VERSION=1.0.0
Frontend .env configuration:
VITE_MCP_SERVER_URL=http://localhost:3333
VITE_WS_SERVER_URL=ws://localhost:3333
Step 3: Start Backend Server
The backend requires TWO processes to run:
- MCP Server (stdio) - Handles MCP protocol commands
- HTTP/WebSocket Server - Serves frontend and manages WebSocket connections
Option A: Run both processes with a single command (Recommended):
npm run dev:all
This starts both servers simultaneously with colored output:
[HTTP] 🚀 Excalidraw MCP Server
[HTTP] HTTP: http://localhost:3333
[HTTP] WebSocket: ws://localhost:3333
[HTTP] Health: http://localhost:3333/health
[MCP] MCP server started successfully
[MCP] Tools registered: element_create, element_update, element_delete, get_canvas_state
Option B: Run processes separately (for debugging):
# Terminal 1: HTTP/WebSocket Server
npm run dev
# Terminal 2: MCP Server (for Claude Desktop integration)
npm run dev:mcp
Available MCP Tools (12 total):
Element Operations:
element_create- Create new elements (rectangle, ellipse, diamond, arrow, text, freedraw, image, frame, etc.)element_update- Update existing element properties (position, size, colors, text, etc.)element_delete- Soft delete elements (mark as deleted without removing from storage)batch_create_elements- Create multiple elements efficiently in a single operation
Canvas Operations:
get_canvas_state- Get all active elements and canvas stateclear_canvas- Remove all elements from canvascanvas_export- Export canvas data in JSON or Excalidraw formatcanvas_import- Import elements into canvas (merge or replace mode)
Group & Layout:
group_create- Group elements together to move as a unitgroup_ungroup- Ungroup previously grouped elements
Element State:
lock_elements- Lock elements to prevent accidental modificationunlock_elements- Unlock previously locked elements
Available MCP Resources:
canvas://main/state- Read canvas state and elementshealth://check- Server health metrics
Step 4: Start Frontend (Optional)
The frontend is optional and runs independently:
cd frontend
npm run dev
Frontend will be available at: http://localhost:5173
Step 5: Test MCP Commands
Test the MCP server using curl or your MCP client:
# Health check
curl http://localhost:3333/health
# Create a rectangle via MCP
curl -X POST http://localhost:3333/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "element_create",
"arguments": {
"type": "rectangle",
"x": 100,
"y": 100,
"width": 200,
"height": 150,
"strokeColor": "#c92a2a",
"backgroundColor": "#ffd43b"
}
}
}'
# Query all elements
curl -X POST http://localhost:3333/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "element_query",
"arguments": {}
}
}'
# Read canvas state
curl -X POST http://localhost:3333/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "resources/read",
"params": {
"uri": "canvas://main/state"
}
}'
Troubleshooting
Problem: Port 3333 already in use
# Change PORT in backend/.env
PORT=3334
WS_PORT=3334
# Update frontend/.env
VITE_MCP_SERVER_URL=http://localhost:3334
VITE_WS_SERVER_URL=ws://localhost:3334
Problem: Module not found errors
# Clean install
rm -rf node_modules package-lock.json
npm install
Problem: TypeScript compilation errors
# Rebuild
npm run build
Docker Deployment
Run the entire system using Docker Compose with hot-reload support for development.
Prerequisites
- Docker 20.10+ and Docker Compose 1.29+
- Ports 3333 (backend) and 8080 (frontend) available
Quick Start
Start all services:
docker-compose up
Frontend: http://localhost:8080 Backend: http://localhost:3333
With rebuild (after code changes):
docker-compose up --build
Detached mode (run in background):
docker-compose up -d
View logs:
# All services
docker-compose logs -f
# Specific service
docker-compose logs -f backend
docker-compose logs -f frontend
Stop services:
docker-compose down
Stop and remove volumes (deletes persisted canvas data):
docker-compose down -v
Architecture
Services:
- backend: Node.js 18 Alpine (MCP server + WebSocket + REST API)
- frontend: Nginx Alpine (Static React SPA)
Volumes:
canvas-data: Persistent canvas storage (survives container restarts)./backend/src: Hot-reload for backend development (read-only mount)
Networking:
- Custom bridge network
excalidraw-network - Frontend depends on backend health check
- Services communicate via service names
Health Checks
Both services have built-in health checks:
# Check backend health
curl http://localhost:3333/health
# Check frontend health
curl http://localhost:8080/health
Docker automatically restarts unhealthy containers.
Development vs Production
Development (with hot-reload):
# docker-compose.yml - backend volumes section
volumes:
- canvas-data:/app/data
- ./backend/src:/app/src:ro # Enabled
Production (no hot-reload):
volumes:
- canvas-data:/app/data
# - ./backend/src:/app/src:ro # Disabled
Comment out hot-reload volumes in production for better performance.
Environment Variables
Override defaults in docker-compose.yml:
environment:
- PORT=3333
- WS_PORT=3333
- NODE_ENV=production
- LOG_LEVEL=info
- VITE_MCP_SERVER_URL=http://localhost:3333
- VITE_WS_SERVER_URL=ws://localhost:3333
Data Persistence
Canvas data persists in Docker volume canvas-data:
# Inspect volume
docker volume inspect excalidraw-mcp_canvas-data
# Backup data
docker run --rm -v excalidraw-mcp_canvas-data:/data -v $(pwd):/backup alpine tar czf /backup/canvas-backup.tar.gz -C /data .
# Restore data
docker run --rm -v excalidraw-mcp_canvas-data:/data -v $(pwd):/backup alpine tar xzf /backup/canvas-backup.tar.gz -C /data
Troubleshooting
Problem: Port 3333 or 8080 already in use
# Change ports in docker-compose.yml
ports:
- "3334:3333" # backend
- "8081:80" # frontend
Problem: Services won't start
# Check logs
docker-compose logs
# Rebuild from scratch
docker-compose down -v
docker-compose build --no-cache
docker-compose up
Problem: Frontend can't connect to backend
# Ensure backend is healthy
docker-compose ps
# Check backend logs
docker-compose logs backend
# Verify network
docker network inspect excalidraw-mcp_excalidraw-network
Problem: Changes not reflecting (hot-reload not working)
# Ensure volume mount is correct
docker-compose config | grep volumes
# Restart services
docker-compose restart
Custom Dockerfile Builds
Backend only:
cd backend
docker build -t excalidraw-mcp-backend .
docker run -p 3333:3333 -v canvas-data:/app/data excalidraw-mcp-backend
Frontend only:
cd frontend
docker build -t excalidraw-mcp-frontend .
docker run -p 8080:80 excalidraw-mcp-frontend
Frontend Standalone Usage
The frontend can be used independently without the backend MCP server. All data is persisted to browser localStorage.
Starting the Frontend
cd frontend
npm run dev
Frontend will be available at: http://localhost:5173
Features
Theme Management
- Click the menu icon (☰) in the top-left
- Select Theme → Choose Light, Dark, or System
- Theme preference is saved to localStorage
Drawing
- Use toolbar on the left to select shapes (rectangle, circle, diamond, arrow, line, text, freedraw)
- Click and drag on canvas to create elements
- Select elements to edit properties (color, stroke, size)
- Use mouse wheel or pinch gesture to zoom
- Click and drag canvas to pan
Persistence
- Canvas automatically saves to localStorage every second
- Viewport position (scroll, zoom) is also persisted
- Refresh page to verify persistence
Export Options
- Click menu icon (☰) → Export
- Export as PNG: High-quality raster image
- Export as SVG: Vector format (scalable, editable)
- Export as JSON: Full Excalidraw format (
.excalidrawfile)
Clear Canvas
- Click menu icon (☰) → Canvas → Clear Canvas
- Confirms before deleting all elements
- Also clears localStorage
Keyboard Shortcuts
Standard Excalidraw shortcuts are available:
V- Selection toolR- RectangleD- DiamondO- EllipseA- ArrowL- LineT- TextDelete- Delete selected elementsCtrl+Z/Cmd+Z- UndoCtrl+Shift+Z/Cmd+Shift+Z- RedoCtrl+D/Cmd+D- DuplicateCtrl+A/Cmd+A- Select all
Integration with Backend
The frontend can sync with the backend in real-time via WebSocket. See Real-Time Sync section below for full details.
Usage
MCP Tools
# Example: Create a rectangle
curl -X POST http://localhost:3333/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "element_create",
"arguments": {
"type": "rectangle",
"x": 100,
"y": 100,
"width": 200,
"height": 150
}
}
}'
More usage examples in the [Quickstart Guide](./specs/001-excalidraw-mcp-server/quicksta
…
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: whallysson
- Source: whallysson/excalidraw-mcp
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.