# Excalidraw Mcp

> A Model Context Protocol (MCP) server for Excalidraw with real-time collaborative frontend

- **Type:** MCP server
- **Install:** `agentstack add mcp-whallysson-excalidraw-mcp`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [whallysson](https://agentstack.voostack.com/s/whallysson)
- **Installs:** 0
- **Category:** [Integrations](https://agentstack.voostack.com/c/integrations)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [whallysson](https://github.com/whallysson)
- **Source:** https://github.com/whallysson/excalidraw-mcp

## Install

```sh
agentstack add mcp-whallysson-excalidraw-mcp
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## 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)

```bash
# 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)

```bash
# 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)

```bash
# 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

```bash
# 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:

```bash
# Separate terminal: MCP Server for Claude Desktop
cd backend
npm run dev:mcp
```

**Claude Desktop Configuration** (`claude_desktop_config.json`):
```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:

```bash
# 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

```bash
cd backend
npm install
```

### Frontend Dependencies

```bash
cd frontend
npm install
```

## Local Setup

### Step 1: Install Dependencies

Install dependencies for both backend and frontend:

```bash
# Backend
cd backend
npm install

# Frontend
cd ../frontend
npm install
```

### Step 2: Configure Environment Variables

Copy the example environment files and configure them:

```bash
# Backend environment
cp backend/.env.example backend/.env

# Frontend environment
cp frontend/.env.example frontend/.env
```

**Backend `.env` configuration:**
```env
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:**
```env
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:
1. **MCP Server** (stdio) - Handles MCP protocol commands
2. **HTTP/WebSocket Server** - Serves frontend and manages WebSocket connections

**Option A: Run both processes with a single command** (Recommended):

```bash
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):

```bash
# 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 state
- `clear_canvas` - Remove all elements from canvas
- `canvas_export` - Export canvas data in JSON or Excalidraw format
- `canvas_import` - Import elements into canvas (merge or replace mode)

**Group & Layout:**
- `group_create` - Group elements together to move as a unit
- `group_ungroup` - Ungroup previously grouped elements

**Element State:**
- `lock_elements` - Lock elements to prevent accidental modification
- `unlock_elements` - Unlock previously locked elements

**Available MCP Resources:**
- `canvas://main/state` - Read canvas state and elements
- `health://check` - Server health metrics

### Step 4: Start Frontend (Optional)

The frontend is optional and runs independently:

```bash
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:

```bash
# 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
```bash
# 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
```bash
# Clean install
rm -rf node_modules package-lock.json
npm install
```

**Problem**: TypeScript compilation errors
```bash
# 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**:
```bash
docker-compose up
```

Frontend: `http://localhost:8080`
Backend: `http://localhost:3333`

**With rebuild** (after code changes):
```bash
docker-compose up --build
```

**Detached mode** (run in background):
```bash
docker-compose up -d
```

**View logs**:
```bash
# All services
docker-compose logs -f

# Specific service
docker-compose logs -f backend
docker-compose logs -f frontend
```

**Stop services**:
```bash
docker-compose down
```

**Stop and remove volumes** (deletes persisted canvas data):
```bash
docker-compose down -v
```

### Architecture

**Services**:
1. **backend**: Node.js 18 Alpine (MCP server + WebSocket + REST API)
2. **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:

```bash
# 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):
```yaml
# docker-compose.yml - backend volumes section
volumes:
  - canvas-data:/app/data
  - ./backend/src:/app/src:ro  # Enabled
```

**Production** (no hot-reload):
```yaml
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`:

```yaml
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`:

```bash
# 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
```bash
# Change ports in docker-compose.yml
ports:
  - "3334:3333"  # backend
  - "8081:80"    # frontend
```

**Problem**: Services won't start
```bash
# 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
```bash
# 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)
```bash
# Ensure volume mount is correct
docker-compose config | grep volumes

# Restart services
docker-compose restart
```

### Custom Dockerfile Builds

**Backend only**:
```bash
cd backend
docker build -t excalidraw-mcp-backend .
docker run -p 3333:3333 -v canvas-data:/app/data excalidraw-mcp-backend
```

**Frontend only**:
```bash
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

```bash
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 (`.excalidraw` file)

**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 tool
- `R` - Rectangle
- `D` - Diamond
- `O` - Ellipse
- `A` - Arrow
- `L` - Line
- `T` - Text
- `Delete` - Delete selected elements
- `Ctrl+Z` / `Cmd+Z` - Undo
- `Ctrl+Shift+Z` / `Cmd+Shift+Z` - Redo
- `Ctrl+D` / `Cmd+D` - Duplicate
- `Ctrl+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

```bash
# 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](https://github.com/whallysson)
- **Source:** [whallysson/excalidraw-mcp](https://github.com/whallysson/excalidraw-mcp)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-whallysson-excalidraw-mcp
- Seller: https://agentstack.voostack.com/s/whallysson
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
