Skip to main content
Glama
patrickcamargo7

excalidash-mcp

README.md
# excalidash-mcp

MCP server for live collaborative drawing on [ExcaliDash](https://github.com/ZimengXiong/ExcaliDash). Draw diagrams, brainstorm, and visualize ideas — changes appear instantly in the browser via Socket.IO.

https://github.com/user-attachments/assets/placeholder-demo.mp4

## Features

- **Live updates** — Elements appear instantly in open browsers, no refresh needed
- **High-level tools** — `add_text`, `add_shape`, `add_arrow` with minimal tokens
- **Scene DSL** — Draw complex diagrams with a compact one-line-per-element syntax
- **Named Elements** — Give elements descriptive IDs (`rect frontend 100,100 ...`) for easy reference
- **Edit & Delete** — Modify or remove elements by name, live
- **Rename** — Rename cryptic auto-generated IDs to descriptive names
- **Version History** — Browse snapshots, restore previous versions (requires [ExcaliDash](https://github.com/ZimengXiong/ExcaliDash) with [PR #138](https://github.com/ZimengXiong/ExcaliDash/pull/138))
- **Library** — Search and place icons/templates from your ExcaliDash library
- **Token-efficient** — ~85% fewer tokens compared to raw Excalidraw JSON

## Prerequisites

You need a running [ExcaliDash](https://github.com/ZimengXiong/ExcaliDash) instance. ExcaliDash is a self-hosted Excalidraw dashboard with user management, REST API, and real-time collaboration.

### 1. Set up ExcaliDash

Follow the [ExcaliDash installation guide](https://github.com/ZimengXiong/ExcaliDash) to get your instance running. Typically:

```bash
git clone https://github.com/ZimengXiong/ExcaliDash.git
cd ExcaliDash
cp .env.example .env  # configure JWT_SECRET, CSRF_SECRET, etc.
docker compose up -d
```

### 2. Configure Nginx (important!)

The default ExcaliDash frontend Nginx config does **not** proxy `/api/` and `/socket.io/` to the backend. You need to add these proxy rules for the MCP adapter (and live collaboration) to work.

Create a custom `nginx.conf` and mount it into the frontend container:

```nginx
server {
    listen 80;
    server_name localhost;

    location / {
        root /usr/share/nginx/html;
        index index.html;
        try_files $uri $uri/ /index.html;
    }

    # API proxy
    location /api/ {
        proxy_pass http://backend:8000/api/;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # Backend routes (auth, drawings, etc.)
    location ~ ^/(auth|csrf-token|drawings|health|collections|admin) {
        proxy_pass http://backend:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # Socket.IO (live collaboration)
    location /socket.io/ {
        proxy_pass http://backend:8000/socket.io/;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 86400;
    }
}
```

Mount it in your `docker-compose.yml`:

```yaml
frontend:
  image: zimengxiong/excalidash-frontend:latest
  volumes:
    - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
```

### 3. Create an agent user

Create a dedicated user for the MCP adapter in ExcaliDash. This keeps agent actions separate from your personal account and shows up as a distinct collaborator on the board.

You can create a user via the ExcaliDash UI or API.

### 4. (Optional) Expose backend port

If the MCP adapter runs on the same machine as ExcaliDash, expose the backend port for direct access (faster than going through Nginx):

```yaml
backend:
  ports:
    - "127.0.0.1:6768:8000"
```

## Installation

```bash
git clone https://github.com/davifernan/excalidash-mcp.git
cd excalidash-mcp
npm install
```

## Configuration

Add to your MCP client config (e.g. `~/.mcp.json` for Claude Code):

```json
{
  "mcpServers": {
    "excalidash": {
      "command": "node",
      "args": ["/path/to/excalidash-mcp/src/index.js"],
      "env": {
        "EXCALIDASH_BACKEND_URL": "http://127.0.0.1:6768",
        "EXCALIDASH_URL": "https://your-excalidash.example.com",
        "EXCALIDASH_EMAIL": "agent@example.com",
        "EXCALIDASH_PASSWORD": "your-agent-password"
      }
    }
  }
}
```

### Behind a reverse proxy?

If your ExcaliDash backend has `TRUST_PROXY=true` (common when behind Nginx/Cloudflare), add these to prevent redirect loops:

```json
{
  "env": {
    "EXCALIDASH_PROXY_PROTO": "https",
    "EXCALIDASH_PROXY_HOST": "your-excalidash.example.com"
  }
}
```

## Tools

### Drawing (token-efficient)

| Tool | Description |
|------|-------------|
| `add_text` | Add text with position, color, size, font |
| `add_shape` | Add rectangle/ellipse/diamond with optional label |
| `add_arrow` | Arrow with head styles (arrow/bar/dot/triangle/none), line styles (solid/dashed/dotted) |
| `draw_scene` | Compact DSL — one element per line |

### Scene DSL

Draw multiple elements in a single call with minimal tokens. **Always give elements descriptive IDs** — this makes updating and deleting easy:

```
# Comments start with #
text title 250,20 size=28 color=blue 'System Architecture'

rect frontend 100,100 200x100 color=blue fill=blue 'Frontend'
rect backend 400,100 200x100 color=green fill=green 'Backend'
arrow fe-to-be 300,150 -> 400,150 color=gray style=dashed 'API'

diamond cache 250,280 120x80 color=orange fill=orange
circle queue 500,280 80x80 color=purple fill=purple
```

**Supported types:** `rect`, `circle`, `diamond`, `arrow`, `line`, `text`

**Colors:** `red`, `blue`, `green`, `orange`, `purple`, `pink`, `yellow`, `gray`, `black` — or any hex code (`#e03131`)

**Arrow options:** `style=dashed`, `start=arrow`, `end=triangle`

### Board Management

| Tool | Description |
|------|-------------|
| `list_boards` | List all boards |
| `create_board` | Create a new board |
| `read_board` | Read elements with IDs (for editing) |
| `clear_board` | Remove all elements |

### Editing

| Tool | Description |
|------|-------------|
| `update_element` | Change any property by element name/ID |
| `delete_elements` | Delete specific elements by name/ID |
| `rename_element` | Rename a cryptic ID to a descriptive name (updates all references) |

### Version History

Requires [ExcaliDash](https://github.com/ZimengXiong/ExcaliDash) with [PR #138](https://github.com/ZimengXiong/ExcaliDash/pull/138) (pending merge).

| Tool | Description |
|------|-------------|
| `board_history` | List version snapshots (ID + timestamp) |
| `restore_version` | Restore a board to a previous snapshot (reversible) |

### Library

| Tool | Description |
|------|-------------|
| `get_library` | Search available icons/templates by name |
| `add_from_library` | Place a library item on the board |

## Environment Variables

| Variable | Required | Description |
|----------|----------|-------------|
| `EXCALIDASH_BACKEND_URL` | Yes | Backend API URL (e.g. `http://127.0.0.1:6768`) |
| `EXCALIDASH_URL` | Yes | Public frontend URL (e.g. `https://draw.example.com`) |
| `EXCALIDASH_EMAIL` | Yes | Agent user email |
| `EXCALIDASH_PASSWORD` | Yes | Agent user password |
| `EXCALIDASH_PROXY_PROTO` | No | Set to `https` if behind reverse proxy with `TRUST_PROXY=true` |
| `EXCALIDASH_PROXY_HOST` | No | Hostname for proxy `Host` header |

## How it works

```
Claude / AI Agent
       │
       │ MCP tool calls (add_text, draw_scene, etc.)
       ▼
┌─────────────────┐
│  excalidash-mcp │  ← enriches elements, calculates text dimensions
│  (MCP Server)   │
└───────┬─────────┘
        │
   ┌────┴────┐
   │         │
   ▼         ▼
Socket.IO   REST API
(live)      (persist)
   │         │
   └────┬────┘
        ▼
┌─────────────────┐
│   ExcaliDash    │  ← self-hosted Excalidraw dashboard
│   Backend       │
└───────┬─────────┘
        │
        ▼
   Browser(s)  ← instant live updates, no refresh
```

## License

MIT