MCP Hub
Back to servers

@sanjibdevnath/mcp-excalidraw-local

Fully local MCP server for Excalidraw with SQLite persistence, multi-tenancy, auto-sync, real-time canvas, and 32 tools

npm44/wk
Stars
1
Updated
Feb 19, 2026

Quick Install

npx -y @sanjibdevnath/mcp-excalidraw-local

MCP Excalidraw Local

CI Docker Build & Push License

A fully local, self-hosted Excalidraw MCP server with SQLite persistence, multi-tenancy, and auto-sync — designed to run entirely on your machine without depending on excalidraw.com.

Run a live Excalidraw canvas and control it from any AI agent. This repo provides:

  • MCP Server: 32 tools over stdio — works with any MCP-compatible client
  • Agent Skill: Portable skill with workflow playbooks, cheatsheets, and helper scripts
  • Live Canvas: Real-time Excalidraw UI synced via WebSocket
  • SQLite Persistence: Elements survive restarts, with versioning and search
  • Multi-Tenancy: Isolated canvases per workspace, auto-detected

Fork notice: This project is forked from yctimlin/mcp_excalidraw and extends it with persistence, multi-workspace support, and numerous UX improvements. Full credit to the original author for the excellent foundation. See What Changed From Upstream for details.

Keywords: Excalidraw MCP server, AI diagramming, local Excalidraw, self-hosted, SQLite persistence, multi-tenant, Mermaid to Excalidraw.

Screenshots

Canvas UI

The live Excalidraw canvas with toolbar, connection status, sync controls, and workspace badge:

Canvas UI

Workspace Switcher

Click the workspace badge to switch between isolated canvases — each workspace has its own set of diagrams:

Workspace Switcher

For a demo of the upstream project (before persistence/multi-tenancy), see the original video by @yctimlin.

Table of Contents

What It Is

This MCP server gives AI agents a full canvas toolkit to build, inspect, and iteratively refine Excalidraw diagrams — including the ability to see what they drew.

The repo contains a single Node.js process that runs:

  • MCP server (stdio): 32 tools for element CRUD, layout, scene awareness, file I/O, snapshots, search, multi-tenancy, and more
  • Canvas server (embedded): web UI + REST API + WebSocket updates at http://localhost:<CANVAS_PORT>
  • SQLite database: persistent storage at ~/.excalidraw-mcp/excalidraw.db

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 MCPThis Project
ApproachPrompt in, diagram out (one-shot)Programmatic element-level control (32 tools)
StateStateless — each call is independentPersistent live canvas with real-time sync
StorageNoneSQLite with WAL mode, versioning, element history
Multi-tenancyNoWorkspace-based isolation, auto-detected
Element CRUDNoFull create / read / update / delete per element
AI sees the canvasNodescribe_scene (structured text) + get_canvas_screenshot (image)
Iterative refinementNo — regenerate the whole diagramDraw → look → adjust → look again, element by element
Layout toolsNoalign_elements, distribute_elements, group / ungroup
File I/ONoexport_scene / import_scene (.excalidraw JSON)
Snapshot & rollbackNosnapshot_scene / restore_snapshot
Mermaid conversionNocreate_from_mermaid
SearchNosearch_elements — full-text search across labels
Design guideread_me cheat sheetread_diagram_guide (colors, sizing, layout, anti-patterns)
Viewport controlCamera animationsset_viewport (zoom-to-fit, center on element, manual zoom)
Live canvas UIRendered inline in chatStandalone Excalidraw app synced via WebSocket
Multi-agentSingle userMultiple agents can draw on the same canvas concurrently
Works without MCPNoYes — 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 Changed From Upstream

This fork extends yctimlin/mcp_excalidraw with the following enhancements:

AreaUpstreamThis Fork
StorageIn-memory (lost on restart)SQLite with WAL mode, versioning, element history
Multi-tenancyNoneWorkspace-based tenant isolation (auto-detected via server.listRoots())
Canvas lifecycleSeparate process (2 terminals)Embedded in MCP process (single node dist/index.js)
Auto-syncManual "Sync to Backend" buttonDebounced auto-sync (3s idle) with manual override
Canvas portHardcoded 3000Configurable via CANVAS_PORT env var
MCP tools2632 (added search, history, tenants, projects)
Workspace switcherNoneDropdown with search in canvas UI
Sync normalizationBound text breaks on reloadElements normalized to MCP format before storage
ProjectsNoneMultiple projects per tenant
Element historyNoneFull version history per element
SearchNoneFull-text search across elements

New MCP Tools (6 added)

ToolDescription
search_elementsFull-text search across element labels and text
element_historyView version history for any element
list_projectsList projects within the active tenant
switch_projectSwitch between projects
list_tenantsList all workspace tenants
switch_tenantSwitch the active workspace tenant

What's New

v1.0 — This Fork (Persistence & Multi-Tenancy)

  • SQLite persistence: Elements, projects, tenants, snapshots, and element versions stored in ~/.excalidraw-mcp/excalidraw.db with WAL mode and busy_timeout for multi-process safety
  • Multi-tenancy: Each workspace gets an isolated canvas. Tenant auto-detected from workspace path via server.listRoots(). UI dropdown with search for switching workspaces
  • Embedded canvas: Canvas server runs inside the MCP process — single node dist/index.js starts everything, stops together
  • Auto-sync with debounce: Canvas changes are automatically persisted after 3s of inactivity. Manual sync button as fallback. Toggle auto-sync on/off
  • Configurable port: CANVAS_PORT env var (default 3000)
  • Sync normalization: Excalidraw's internal bound-text representation is normalized to MCP format before storage, preventing text overflow/detachment on reload
  • 6 new MCP tools: search_elements, element_history, list_projects, switch_project, list_tenants, switch_tenant
  • Updated agent skill: Comprehensive workflow playbook with iterative write-check-review cycle, sizing rules, anti-patterns, and quality checklist
  • Workspace switcher UI: Click "Workspace: ..." badge to search and switch between workspaces

v2.0 — Canvas Toolkit (upstream)

  • 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
  • Viewport control: set_viewport with scrollToContent, scrollToElementId, or manual zoom/offset
  • 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
  • Fixed all previously known issues: align_elements / distribute_elements fully implemented, points type normalization, removed invalid label type, ungroup_elements now errors on failure

v1.x (upstream)

  • 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
  • Bugfixes: batch create now preserves element ids (fixes update/delete after batch); frontend entrypoint fixed

Architecture

Architecture

  • Single process: The MCP server embeds the canvas server. Starting the MCP starts both; stopping it stops both.
  • SQLite: Stored at ~/.excalidraw-mcp/excalidraw.db by default. WAL mode + busy_timeout for multi-process safety.
  • Multi-tenancy: Each workspace gets an isolated tenant (SHA-256 hash of workspace path). The UI shows a workspace switcher dropdown with search.

Quick Start

Option A: NPM (recommended)

npx @sanjibdevnath/mcp-excalidraw-local

Or install globally:

npm install -g @sanjibdevnath/mcp-excalidraw-local
mcp-excalidraw-local

Option B: From source

Prerequisites: Node >= 18, npm or pnpm

git clone https://github.com/sanjibdevnathlabs/mcp-excalidraw-local.git
cd mcp-excalidraw-local

# Install dependencies (pnpm or npm)
pnpm install
pnpm rebuild better-sqlite3 esbuild

# Build frontend + server
pnpm run build

The MCP server is typically started by your MCP client — see Configuration. To run manually:

node dist/index.js

This starts the MCP server (stdio) and the canvas server. Open http://localhost:3000 in your browser.

Quick Start (Docker)

Canvas server:

docker run -d -p 3000:3000 --name mcp-excalidraw-canvas sanjibdevnath/mcp-excalidraw-local-canvas:latest

MCP server (stdio) is typically launched by your MCP client. If you want a local container, use sanjibdevnath/mcp-excalidraw-local:latest.

Configuration

This is a standard MCP server communicating over stdio. It works with any MCP-compatible client (Cursor, Claude Desktop, Claude Code, Codex CLI, OpenCode, Gemini, or any other agent that supports the Model Context Protocol).

JSON config (most clients)

Add this to your client's MCP configuration file:

{
  "mcpServers": {
    "excalidraw-canvas": {
      "command": "node",
      "args": ["/absolute/path/to/mcp-excalidraw-local/dist/index.js"],
      "env": {
        "CANVAS_PORT": "3000"
      }
    }
  }
}

Replace /absolute/path/to/mcp-excalidraw-local with the actual path where you cloned and built the repo.

CLI-based registration

# Example for Claude Code
claude mcp add excalidraw-canvas --scope user \
  -e CANVAS_PORT=3000 \
  -- node /absolute/path/to/mcp-excalidraw-local/dist/index.js

Docker

{
  "mcpServers": {
    "excalidraw-canvas": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "-e", "CANVAS_PORT=3000",
        "sanjibdevnath/mcp-excalidraw-local:latest"
      ]
    }
  }
}

Note: For Docker on Linux, you may need --add-host=host.docker.internal:host-gateway.

Key points

  • Single process — The canvas server is embedded. No separate terminal or process needed.
  • Browser required for screenshotsexport_to_image and get_canvas_screenshot rely on the frontend. Open http://localhost:3000 in a browser.

Environment Variables

VariableDescriptionDefault
CANVAS_PORTPort for the embedded canvas server3000
EXCALIDRAW_DB_PATHPath to the SQLite database file~/.excalidraw-mcp/excalidraw.db
EXCALIDRAW_EXPORT_DIRAllowed directory for file exportsprocess.cwd()
EXPRESS_SERVER_URLCanvas server URL (only if running canvas separately)http://localhost:3000
ENABLE_CANVAS_SYNCEnable real-time canvas synctrue

Multi-Tenancy (Workspaces)

Each workspace (codebase) gets an isolated canvas. The tenant is identified by a SHA-256 hash of the workspace path.

How it works

  1. Auto-detection: When the MCP starts, it calls server.listRoots() to get the actual workspace path from the MCP client. This is hashed to create a unique tenant ID.
  2. Per-request scoping: Every HTTP request includes an X-Tenant-Id header. The canvas server uses this to scope all CRUD operations to the correct tenant.
  3. UI switcher: The canvas UI shows a "Workspace: <name>" badge. Click it to open a dropdown with all known workspaces, complete with search.
  4. Multi-instance safe: SQLite WAL mode with busy_timeout = 5000ms handles concurrent access from multiple client instances.

Projects within a tenant

Each tenant can have multiple projects (collections of elements). Use the list_projects and switch_project MCP tools, or manage via the REST API.

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 — including an iterative write-check-review cycle, sizing rules, color palettes, and anti-patterns
  • Cheatsheet (references/cheatsheet.md): MCP tool and REST API reference for all 32 tools
  • 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

Copy the skill folder to your agent's skill directory:

# Claude Code
mkdir -p ~/.claude/skills
cp -R skills/excalidraw-skill ~/.claude/skills/excalidraw-skill

# Cursor
mkdir -p ~/.cursor/skills
cp -R skills/excalidraw-skill ~/.cursor/skills/excalidraw-skill

# Codex CLI
mkdir -p ~/.codex/skills
cp -R skills/excalidraw-skill ~/.codex/skills/excalidraw-skill

# Or any agent that supports a skills directory
cp -R skills/excalidraw-skill /path/to/your/agent/skills/

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 (32 Total)

CategoryTools
Element CRUDcreate_element, get_element, update_element, delete_element, query_elements, batch_create_elements, duplicate_elements
Layoutalign_elements, distribute_elements, group_elements, ungroup_elements, lock_elements, unlock_elements
Scene Awarenessdescribe_scene, get_canvas_screenshot
File I/Oexport_scene, import_scene, export_to_image, export_to_excalidraw_url, create_from_mermaid
State Managementclear_canvas, snapshot_scene, restore_snapshot
Viewportset_viewport
Design Guideread_diagram_guide
Resourcesget_resource
Search & Historysearch_elements, element_history
Multi-Tenancylist_tenants, switch_tenant
Projectslist_projects, switch_project

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

Testing

Health check

curl http://localhost:3000/health

MCP Inspector

List tools:

npx @modelcontextprotocol/inspector --cli \
  -e CANVAS_PORT=3000 -- \
  node dist/index.js --method tools/list

Create a rectangle:

npx @modelcontextprotocol/inspector --cli \
  -e CANVAS_PORT=3000 -- \
  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

If you use a browser automation tool for UI checks:

# Open the canvas and take a screenshot for verification
open http://127.0.0.1:3000
# Or use agent-browser, Playwright, Puppeteer, etc.

Troubleshooting

  • Canvas not loading: Ensure CANVAS_PORT isn't occupied by another process. Check lsof -i :3000.
  • Canvas not updating: Confirm the MCP process is running and the browser is connected (check the status dot in the header).
  • Wrong workspace shown: The MCP uses server.listRoots() to detect the workspace. Restart your MCP client if the workspace changed.
  • Elements missing after restart: Check ~/.excalidraw-mcp/excalidraw.db exists. If you previously ran the upstream (in-memory) version, data wasn't persisted.
  • Port conflict with multiple instances: Set different CANVAS_PORT values for each workspace, or rely on multi-tenancy (same port, different tenants).
  • Updates/deletes fail after batch creation: Ensure you are on a build that includes the batch id preservation fix.

Known Issues / TODO

All previously listed bugs from the upstream have been fixed. Remaining items:

  • Image export requires a browser: export_to_image and get_canvas_screenshot rely on the frontend rendering. The canvas UI must be open in a browser.
  • export_to_excalidraw_url blocked: Organizations that block excalidraw.com cannot use shareable URL export. Use export_scene for local .excalidraw files instead.

Contributions welcome!

Development

# Type check
pnpm run type-check

# Full build (frontend + server)
pnpm run build

# Dev mode (watch)
pnpm run dev

Database

SQLite database: ~/.excalidraw-mcp/excalidraw.db

Override with EXCALIDRAW_DB_PATH environment variable.

REST API

The canvas server exposes a REST API alongside the WebSocket interface:

MethodEndpointDescription
GET/healthHealth check
GET/api/elementsList all elements
POST/api/elementsCreate an element
PUT/api/elements/:idUpdate an element
DELETE/api/elements/:idDelete an element
POST/api/elements/syncSync all elements (bulk upsert)
GET/api/tenantsList all tenants
GET/api/tenant/activeGet the active tenant
PUT/api/tenant/activeSet the active tenant

All endpoints accept an X-Tenant-Id header for per-request tenant scoping.

Credits

This project is forked from yctimlin/mcp_excalidraw — an excellent Excalidraw MCP server with a live canvas, 26 tools, real-time WebSocket sync, Mermaid conversion, and a comprehensive agent skill. Full credit to @yctimlin for the original design and implementation.

This fork adds SQLite persistence, multi-tenancy, auto-sync, embedded canvas lifecycle, and workspace management on top of that foundation.

Licensed under MIT.

Reviews

No reviews yet

Sign in to write a review