No description
  • JavaScript 48.9%
  • TypeScript 47.2%
  • HTML 3.1%
  • Dockerfile 0.8%
Find a file
Mike Bros 1953a179b5
All checks were successful
CI / build-and-test (20.x) (push) Successful in 2m32s
Build Canvas Image / build-and-push (push) Successful in 4m10s
Merge pull request 'Release v1.1.0 — Neptune Customizations' (#6) from release/1.1.0 into main
Reviewed-on: #6
Reviewed-by: Mike Bros <dev@bros.ninja>
2026-03-19 15:01:02 +00:00
.forgejo/workflows ci: remove explicit container block from build-canvas workflow 2026-03-19 13:11:10 +00:00
frontend refactor: replace express-openid-connect with hand-rolled OIDC using openid-client 2026-03-19 14:04:25 +00:00
skills/excalidraw-skill Codex/issue 59 autosync diagram quality (#61) 2026-03-06 14:27:40 +08:00
src chore(release): bump version to 1.1.0, fix zod schema coercion 2026-03-19 14:24:15 +00:00
.dockerignore update docker files 2025-10-31 16:07:51 +00:00
.gitignore Refactor Excalidraw element conversion to correctly combine image and non-image elements, update skill connection mode documentation, and add evaluation configuration. 2026-03-05 13:45:34 +08:00
claude_desktop_config.json support npx 2025-05-12 22:27:24 +08:00
demo.gif add gif demo 2026-02-14 13:23:52 +08:00
docker-compose.yml update docker files 2025-10-31 16:07:51 +00:00
Dockerfile update docker files 2025-10-31 16:07:51 +00:00
Dockerfile.canvas update docker files 2025-10-31 16:07:51 +00:00
LICENSE Add MIT License, update project name and description in package.json, enhance README.md with installation instructions, and modify index.js for CLI support 2025-07-11 19:52:18 +00:00
package-lock.json refactor: replace express-openid-connect with hand-rolled OIDC using openid-client 2026-03-19 14:04:25 +00:00
package.json chore(release): bump version to 1.1.0, fix zod schema coercion 2026-03-19 14:24:15 +00:00
README.md docs: add Forgejo CI badges to README 2026-03-19 14:28:33 +00:00
tsconfig.json Refactor project structure and enhance TypeScript support 2025-08-20 15:31:42 +00:00
vite.config.js Refactor Excalidraw element conversion to correctly combine image and non-image elements, update skill connection mode documentation, and add evaluation configuration. 2026-03-05 13:45:34 +08:00

Excalidraw MCP Server

CI Canvas Build License

A self-hosted Excalidraw canvas with MCP (Model Context Protocol) integration, OIDC authentication, and real-time collaboration. Fork of yctimlin/mcp_excalidraw with significant additions for production deployment.

What This Fork Adds

  • OIDC Authentication — Login via Authentik (or any OIDC provider) with PKCE, signed session cookies
  • API Token AuthMCP_AUTH_TOKEN bearer token for MCP agent access to write APIs
  • View-Only Public Access — Unauthenticated visitors can watch the canvas in real-time (pan/zoom only)
  • Dark Mode — Default dark theme with persistence across reloads
  • Server-Side Libraries — Mount .excalidrawlib files and they auto-load for all users
  • Library Persistence — Library items saved to localStorage, survive page reloads
  • Production Docker Setup — Healthcheck, reverse proxy support, hairpin NAT workarounds

Quick Start (Docker)

# compose.yaml
services:
  excalidraw-canvas:
    image: git.bros.ninja/mike/mcp_excalidraw/canvas:latest
    ports:
      - 8942:3000
    environment:
      - NODE_ENV=production
      - PORT=3000
      - HOST=0.0.0.0
      - LIBRARIES_DIR=/libraries
      - MCP_AUTH_TOKEN=${MCP_AUTH_TOKEN}
      # OIDC (optional — omit to disable)
      - OIDC_ISSUER_URL=${OIDC_ISSUER_URL:-}
      - OIDC_CLIENT_ID=${OIDC_CLIENT_ID:-}
      - OIDC_SECRET=${OIDC_SECRET:-}
      - OIDC_BASE_URL=${OIDC_BASE_URL:-}
      - OIDC_COOKIE_SECRET=${OIDC_COOKIE_SECRET:-}
    volumes:
      - ./libraries:/libraries:ro
    restart: unless-stopped
    healthcheck:
      test:
        [
          "CMD-SHELL",
          'node -e "fetch(''http://localhost:3000/health'').then(r=>{if(!r.ok)process.exit(1)}).catch(()=>process.exit(1))"',
        ]
      interval: 30s
      timeout: 10s
      retries: 3
# Generate an auth token
openssl rand -hex 32 > .env
echo "MCP_AUTH_TOKEN=$(cat .env)" > .env

docker compose up -d

Open http://localhost:8942.

Quick Start (Local)

npm ci
npm run build

# Terminal 1: canvas server
PORT=3000 npm run canvas

# Terminal 2: MCP server (stdio)
EXPRESS_SERVER_URL=http://localhost:3000 node dist/index.js

Authentication

How It Works

The canvas has three access levels:

Level Access How
Public View canvas, pan/zoom, WebSocket updates No auth needed
MCP Agent Full API read/write Authorization: Bearer <MCP_AUTH_TOKEN> header
OIDC User Full UI read/write Login via /auth/login

All write API routes (POST/PUT/DELETE) require either a valid bearer token or an OIDC session. Read routes (GET, WebSocket) are public.

MCP Agent Token

Set MCP_AUTH_TOKEN in both the canvas container and your MCP client config:

{
  "mcpServers": {
    "excalidraw": {
      "command": "node",
      "args": ["/path/to/mcp_excalidraw/dist/index.js"],
      "env": {
        "EXPRESS_SERVER_URL": "http://localhost:8942",
        "ENABLE_CANVAS_SYNC": "true",
        "MCP_AUTH_TOKEN": "your-token-here"
      }
    }
  }
}

OIDC (Authentik)

  1. Create an OAuth2/OIDC Provider in Authentik
  2. Set redirect URI: https://your-domain.com/auth/callback
  3. Scopes: openid profile email
  4. Add to .env:
OIDC_ISSUER_URL=https://auth.example.com/application/o/excalidraw/
OIDC_CLIENT_ID=your-client-id
OIDC_SECRET=your-client-secret
OIDC_BASE_URL=https://your-domain.com
OIDC_COOKIE_SECRET=$(openssl rand -hex 32)

Works with any standard OIDC provider — not Authentik-specific.

Libraries

Drop .excalidrawlib files into the libraries/ directory (mounted at /libraries in the container). They're automatically loaded for all users on page load and merged with any locally-saved libraries.

Environment Variables

Variable Description Default
PORT Canvas server port 3000
HOST Bind address localhost
EXPRESS_SERVER_URL Canvas URL (MCP client) http://localhost:3000
ENABLE_CANVAS_SYNC Real-time canvas sync true
MCP_AUTH_TOKEN Bearer token for MCP agent auth (none — auth disabled)
LIBRARIES_DIR Path to .excalidrawlib files /libraries
OIDC_ISSUER_URL OIDC provider discovery URL (none — OIDC disabled)
OIDC_CLIENT_ID OIDC client ID
OIDC_SECRET OIDC client secret
OIDC_BASE_URL Public URL for redirect URI
OIDC_COOKIE_SECRET Session cookie encryption key

MCP Tools (26 Total)

Category Tools
Element CRUD create_element, get_element, update_element, delete_element, query_elements, batch_create_elements, duplicate_elements
Layout align_elements, distribute_elements, group_elements, ungroup_elements, lock_elements, unlock_elements
Scene Awareness describe_scene, get_canvas_screenshot
File I/O export_scene, import_scene, export_to_image, export_to_excalidraw_url, create_from_mermaid
State Management clear_canvas, snapshot_scene, restore_snapshot
Viewport set_viewport
Design Guide read_diagram_guide
Resources get_resource

Reverse Proxy Notes

When running behind nginx/caddy with TLS termination:

  • The server has trust proxy enabled — X-Forwarded-Proto is respected for cookie security
  • If your OIDC provider resolves to a public IP that hairpins through your router, add extra_hosts to point it at the LAN IP:
extra_hosts:
  - "auth.example.com:192.168.1.100"

Upstream

Forked from yctimlin/mcp_excalidraw. The upstream provides the core MCP server, canvas UI, WebSocket sync, and 26 MCP tools. This fork adds authentication, dark mode, library management, and production deployment features.

License

MIT