excalidraw-room-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| EXCALIDRAW_ROOM_DEBUG | No | Set to 1 to enable diagnostics on stderr. | 0 |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": true
} |
| resources | {
"listChanged": true
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| create_roomA | Create a new empty live-collaboration room, join it, and return the excalidraw.com link for a person to open. The link contains the encryption key; share it only with people who should see the drawing. The result states the handle this server took in the room. |
| join_roomA | Join an existing excalidraw.com live-collaboration room from its link (the URL with #room=,). Loads the current scene from a connected peer, or from the room's persisted copy if nobody else is present. The result states the handle this server took in the room. |
| show_roomA | Render the current room as a canvas in the chat. Returns a short summary as text - the room link, connection state, peer and element counts, and the pending mentions addressed to this agent with the ids of the elements around each. The canvas view fetches the elements for itself, so they never pass through this result unless you ask: pass include: "json" only if you need the element array in the text; read_scene with ids or near is the cheaper way to inspect elements. Pass link only to render a room this server is not in - it is read from a read-only viewer and the current room is untouched; without it the current room is used, which is what you want. The in-chat view depends on the host; prefer open_room to watch the canvas. |
| open_roomA | Open the room on excalidraw.com in the default browser; the primary way for a person to watch the canvas live. Returns the link, the connection state, and the peer and element counts. Pass link only to open a room this server is not in - it is joined first; without it the current room is used. |
| room_statusC | Connection state, the handle this server took in the room, the room's nearbyRadius and agentReplyDepth, the session's answerQuestions policy, the peers with their handles and whether each is an agent or a browser, the rooms this server is holding read-only viewers for, and scene counters for the current room. |
| read_sceneA | Read the current drawing. 'summary' gives one line per element with position, size, text, and a sampled path for freehand strokes. 'json' returns the full Excalidraw element array as compact JSON. Filter to keep the response small: 'ids' returns just those elements (unknown ids are named back), and 'near' returns one element plus everything within a radius of it. |
| snapshot_sceneA | Render a region of the room to a PNG and see it. Use it whenever the drawing itself is the question: to read hand-drawn content (handwriting, sketched boxes, freehand arrows) that reaches you as point arrays and is otherwise unreadable, to answer "what does this look like", and after moving, spacing or grouping elements to check whether anything still overlaps and the groups read as intended. Select with ids, near (one element and its neighbourhood), or bbox; with no selector the whole scene is rendered. The text block after the image gives the bounding box in scene coordinates, the scale, the pixel size and the ids of the elements drawn, so you can map what you see back to read_scene ids and near queries. Shapes, lines, arrows, freehand strokes and text are drawn flat, without the hand-drawn wobble the canvas shows; images, frames and embeds are drawn as a labelled dashed box and named on a placeholders line. |
| add_elementsA | Add elements to the drawing from compact specs. Shapes take x, y, width, height and an optional label. Arrows take start/end element ids (edges are computed) or absolute points. Any element may take a link (a URL), which makes it clickable on the canvas. Later specs may reference ids of earlier specs in the same call. Pass place instead of x and y to have the server find a free slot beside an element or inside a cluster, so two agents drawing at once never overlap; the result reports the coordinates it chose. The change reaches connected peers immediately and the room's stored copy shortly after; a result line beginning NOT PERSISTED means the stored copy is behind and the server is retrying in the background. |
| add_raw_elementsA | Add complete Excalidraw elements verbatim (the JSON shape from an .excalidraw file). Missing version fields are filled in; fractional indices are assigned if absent. An element carrying customData is stamped with this server's handle as its author, keeping the keys it came with; an element with no customData is left unattributed, so a scene imported from a file still reads as the work of whoever drew it. Hosts cap tool-argument size, so keep each call's arguments under the limit in README Limits (4 KB on Claude Desktop, 16 KB on Claude Code) and send a large scene as several batches; a later batch may reference ids from an earlier one. The change reaches connected peers immediately and the room's stored copy shortly after; a result line beginning NOT PERSISTED means the stored copy is behind and the server is retrying in the background. |
| update_elementsA | Patch existing elements by id. 'set' is merged over the element; version and nonce are bumped. 'set' accepts any element field, including link (a URL, or null to remove it). Changing 'text' or 'fontSize' on a text element re-measures it unless width/height are given, keeps originalText in step, and, for a label bound to a shape, re-centres it and grows the shape to fit so the canvas redraws the new label. Changing 'x', 'y', 'width' or 'height' carries the element's bound label with it and re-computes the endpoint of every arrow bound to it, leaving each arrow's other end alone; use translate_elements to move a shape with its group, its frame's children and the arrows between moved shapes. An element another agent in the room drew is left alone and reported as refused unless force is true; a person's elements and those of an agent that has left are never guarded. The change reaches connected peers immediately and the room's stored copy shortly after; a result line beginning NOT PERSISTED means the stored copy is behind and the server is retrying in the background. |
| translate_elementsA | Move elements by a delta, carrying everything that must travel with them: each element's bound label, every other member of a group the ids belong to, the children of a moved frame, and any arrow bound at both ends to elements that are moving. An arrow bound at one end is re-attached to the moved shape instead of moved, and reported on its own line. Each element moves exactly once however many ways the closure reaches it. The result reports how many moved and which ids the closure added. An element another agent in the room drew is left alone and reported as refused unless force is true; a person's elements and those of an agent that has left are never guarded. |
| delete_elementsA | Soft-delete elements by id (Excalidraw keeps tombstones so peers converge). An element another agent in the room drew is left alone and reported as refused unless force is true; a person's elements and those of an agent that has left are never guarded. The change reaches connected peers immediately and the room's stored copy shortly after; a result line beginning NOT PERSISTED means the stored copy is behind and the server is retrying in the background. |
| wait_for_mentionA | Block until someone writes a text element addressed to this agent on the canvas, then return it with the elements around it. With no tag it answers to its own handle and to the '@claude' broadcast tag. Returns 'no mention' after timeoutSeconds so the caller can loop. A mention is reported once it has stopped changing for about 1.5s. Returning it also marks it seen on the canvas (amber stroke and a marker) so the person knows the note landed; pass autoSeen false to poll without touching the drawing. Acknowledge it with acknowledge_mention when done, which removes the handled note from the canvas; reply about the work in chat. |
| list_mentionsA | List every pending (unacknowledged) mention addressed to this agent on the canvas right now, each with its nearby elements. With no tag it answers to its own handle and to the '@claude' broadcast tag. Mentions surfaced here are marked seen on the canvas as wait_for_mention does; pass autoSeen false to look without touching the drawing. Pass includeHandled true to also list the notes this server acknowledged and left on the canvas, marked handled, so they can be found and cleaned up. |
| acknowledge_mentionA | Mark a mention as handled so it is not returned again. By default the text element is removed from the canvas (soft-deleted): the seen marker already told the person it landed and the drawing is the evidence it was done. Say what you did in chat, not on the canvas - artefacts of the work belong there, prose about it does not. Pass status "out of scope" or "see chat" to keep the element instead, greyed with one check mark, and draw that status under it on its own grey line reading "claude: " - use it when the person has to read the outcome where they wrote the request. Pass keep true to keep it greyed with a check mark and draw nothing. Pass reply (up to 400 characters) when the request is unclear: your question is drawn on the same line under it, as "claude: ", so the person answers where they asked. A reply to a mention another agent wrote is addressed to that agent by default, as "claude: @ ", so it reaches that agent as a mention of its own; replyTo addresses it to a different handle instead, and the room's agentReplyDepth bounds how far such a chain runs. Pass answer (up to 400 characters) for a knowledge question, while set_mention_policy has answering on: the text element is replaced by a yellow post-it in its place, holding the question, your answer wrapped to 360 px and your handle, and source puts a public URL behind it. Whatever you were given, the person's own words are left exactly as they wrote them. status, reply and answer exclude each other. Editing the text makes the mention pending again and what you wrote comes back with it. |
| set_mention_policyA | Turn knowledge answers on or off for this session. With answerQuestions true, a mention that asks a question - a definition, a comparison, a critique of what is on the canvas - may be answered on the canvas with acknowledge_mention answer instead of being acknowledged "out of scope"; reading the person's accounts, sending or posting anything, and acting outside the room stay out of scope either way, and an answer is built from the mention's own words and public knowledge only, never from the conversation. The board is visible to everyone holding the room link: never write client-identifiable, personal, confidential or credential data on the canvas. The flag is held in memory only: it is off when this server starts, a person turns it on by asking in chat, and joining a room or restarting turns it off again. Nothing is written to disk, so this tool call is the only record that it was asked for. room_status and poll_room report answerQuestions. |
| poll_roomA | Cheap state probe: connection state, sceneVersion, the peers, the ids and text of the pending mentions addressed to this agent, and whether the scene moved since a version you pass. Use it while you are working in a turn to notice a change without a full show_room; use wait_for_mention when you are handing the turn back to a person. |
| leave_roomA | Disconnect from the current room. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
| Excalidraw room canvas | Live read-only view of the Excalidraw room this server has joined. |
TDQS
Scored across 18 tools
Most tools target distinct actions (create/join/leave room, add/update/delete elements, wait/list/acknowledge mentions). A few pairs blur: room_status vs poll_room (both status probes) and snapshot_scene vs show_room (both render visuals), plus update_elements vs translate_elements overlap on movement. Descriptions do address these distinctions, but boundaries are not perfectly crisp.
All 18 tools use consistent snake_case with a predictable verb_or_noun + resource pattern (open_room, read_scene, delete_elements, wait_for_mention, create_room). No mixing of camelCase or stray conventions. Names are readable and predictable throughout.
18 tools is on the heavier side (16-25 band), but the domain genuinely spans room lifecycle, scene read/write, element CRUD, and a full mention workflow. Each tool maps to a real operation, though a couple of status/render tools could arguably be merged.
Full lifecycle coverage: room create/join/leave/open/status, scene read/snapshot/show, element add/add_raw/update/translate/delete, and a complete mention cycle (wait/list/acknowledge/policy). No obvious dead ends for the stated live-collaboration purpose.