# Canvs MCP Server — Documentation MCP server for creating and managing collaborative whiteboards (Excalidraw-based canvases). ## Connection - **Endpoint:** `POST /mcp` - **Transport:** Streamable HTTP (stateless) - **Protocol:** [Model Context Protocol](https://modelcontextprotocol.io) ### Config example (Claude Desktop / Claude Code) ```json { "mcpServers": { "canvs": { "url": "https:///mcp" } } } ``` ## Core concepts **Room** — a temporary collaborative canvas with a unique URL. Anyone with the link can view and edit it in real time. Rooms expire after a configurable timeout (default: 1 hour, max: 24 hours). **Element** — a shape on the canvas: rectangle, ellipse, diamond, arrow, line, text, or image. Each element has an `id`, position (`x`, `y`), size (`width`, `height`), and visual properties. **Room URL** — returned as `url` when a room is created. Format: `https://canvs.io/?room=`. Google Drive boards use `https://canvs.io/gdrive?id=`. Tool calls should pass only `room_id`; extract it from the URL when needed. ## Tools ### get_guide Returns detailed instructions for the LLM on how to use the tools effectively (tool selection strategy, workflow tips, examples). No parameters. --- ### add_elements Creates a new canvas or adds elements to an existing one. | Parameter | Type | Required | Description | | ---------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------ | | `room_id` | string | no | Room ID. If omitted — creates a new canvas. Extract from URLs as `?room=[room_id]` or `/gdrive?id=[room_id]` | | `elements` | array | **yes** | Array of element objects (see [Element properties](#element-properties)) | | `timeout` | number | no | Room lifetime in seconds (1–86400, default: 3600) | **Returns:** `created`, `count`, `url`, `room_id`, `elements`, `appState` — same shape for both new and existing rooms. --- ### add_elements_from_mermaid Creates a canvas from a Mermaid diagram, or adds a Mermaid diagram to an existing canvas. Supports: `flowchart`, `graph`, `flowchart-elk`, `sequenceDiagram`, `classDiagram`, `classDiagram-v2`, `stateDiagram`, `stateDiagram-v2`, `erDiagram`, `journey`, `gantt`, `pie`, `gitGraph`, `mindmap`, `timeline`, `C4Context`, `C4Container`, `C4Component`, `C4Dynamic`, `C4Deployment`, `sankey`, `sankey-beta`, `quadrantChart`, `xychart`, `xychart-beta`, `requirement`, `requirementDiagram`, `kanban`, `architecture`, `block`, `block-beta`, `packet`, `packet-beta`, `radar-beta`, `treemap`, `info`. | Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------ | | `room_id` | string | no | Room ID. If omitted — creates a new canvas. Extract from URLs as `?room=[room_id]` or `/gdrive?id=[room_id]` | | `mermaid` | string | **yes** | Mermaid diagram definition | | `config` | object | no | Mermaid config: `flowchart.curve` (`linear` / `basis`), `maxEdges`, `maxTextSize` | | `timeout` | number | no | Room lifetime in seconds (1–86400, default: 3600) | --- ### update_elements Updates properties of existing elements by ID. | Parameter | Type | Required | Description | | ---------- | ------ | -------- | ----------------------------------------------------- | | `room_id` | string | **yes** | Room ID | | `elements` | array | **yes** | Array of objects, each with `id` and fields to update | --- ### delete_elements Removes elements from a canvas by ID. | Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------------------------ | | `room_id` | string | **yes** | Room ID | | `ids` | array | **yes** | Array of element IDs to delete | --- ### query_elements Returns elements from a canvas, optionally filtered. Works without a browser open — reads from the server-side scene cache. Only fails if the room never had a scene saved (e.g. brand-new empty room that no browser has ever joined). | Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------------------------------------------------ | | `room_id` | string | **yes** | Room ID | | `type` | string | no | Filter by element type | | `filter` | object | no | Additional key-value filters (e.g. `{"locked": true}`) | --- ## Element properties Used in `add_elements` and `update_elements`. | Property | Type | Default | Description | | ----------------- | ------- | ------------- | ------------------------------------------------------------------------------- | | `id` | string | auto | Unique ID. Set explicitly if arrows will connect to this element | | `type` | string | — | `rectangle`, `ellipse`, `diamond`, `arrow`, `line`, `text`, `image`, `freedraw` | | `x` | number | — | X coordinate | | `y` | number | — | Y coordinate | | `width` | number | 100 | Width in pixels | | `height` | number | 100 | Height in pixels | | `strokeColor` | string | `#1e1e1e` | Stroke color (hex) | | `backgroundColor` | string | `transparent` | Fill color (hex or `transparent`) | | `fillStyle` | string | `solid` | `solid`, `hachure`, or `cross-hatch` | | `strokeWidth` | number | 2 | Stroke width in pixels | | `roughness` | number | 1 | 0 = architect, 1 = artist, 2 = cartoonist | | `opacity` | number | 100 | 0–100 | | `locked` | boolean | false | Lock element from editing | ### Text properties | Property | Type | Default | Description | | ------------- | ------ | ------- | -------------------------------------------------------------------------- | | `text` | string | — | Text content | | `fontSize` | number | 20 | Font size | | `fontFamily` | number | 5 | 5 = Excalifont, 6 = Nunito, 7 = Lilita One, 8 = Comic Shanns | | `containerId` | string | — | ID of a shape to place text inside. Set `x`, `y` to `0` for auto-centering | ### Arrow/line properties | Property | Type | Description | | -------------- | ---------- | ----------------------------------------------------------------------------- | | `points` | number[][] | Point coordinates relative to element `x`, `y`. Example: `[[0,0], [200,100]]` | | `startBinding` | object | Bind arrow start to a shape: `{elementId, focus, gap}` | | `endBinding` | object | Bind arrow end to a shape: `{elementId, focus, gap}` | | `label` | string | Text label displayed on the arrow | Binding object fields: - `elementId` (string) — ID of the target shape - `focus` (number) — position on the edge, -1 to 1, 0 = center - `gap` (number) — gap from shape edge in pixels (default: 8) ## Typical workflow 1. **Create** a canvas with `add_elements` or `add_elements_from_mermaid` (no `room_id` → new room) 2. If the user did not mention an existing board or room, do not ask for one; just create a new room 3. If a previous Canvs tool result or assistant message in the same chat already contains a `room_id`, reuse it for follow-up tool calls. If only a URL is present, extract `room_id` from `https://[host]/?room=[room_id]` or `https://[host]/gdrive?id=[room_id]`. 4. **Read** the canvas state with `query_elements` (works without a browser) 5. **Modify** using `update_elements`, `delete_elements`, or add more elements — all work without a browser 6. **Adjust structure manually** with `update_elements` when you need to reposition or lock specific items > All tools work without a browser — they read and write directly to the server-side scene cache.