cnvs.app exposes a public Model Context Protocol endpoint at https://cnvs.app/mcp. Streamable HTTP transport, JSON-RPC 2.0 over POST, server-pushed notifications over a GET SSE stream.
https://cnvs.app/mcp2025-06-18{
"mcpServers": {
"cnvs": {
"type": "http",
"url": "https://cnvs.app/mcp"
}
}
}
claude mcp add --transport http cnvs https://cnvs.app/mcp
open_board(url_or_id) — resolve to canonical ID, create if missing, auto-subscribe the session to state.json.get_board(board_id) — full JSON snapshot. Heavy base64 payloads (>8 kB) are elided.get_preview(board_id) — compact SVG render.add_text({...}), add_link({...}), add_image({...}), draw_stroke({...}) — mutations.move({board_id, id, kind?, x, y}) — reposition; kind ∈ text | link | line | image.erase({board_id, id, kind}) — delete; kind ∈ text | line | image.wait_for_update({board_id, timeout_ms?}) — long-poll for the next edit. Clamped to [1000, 55000]; default 25000.cnvs://board/{id}/state.json — full JSON snapshot. Subscribable.cnvs://board/{id}/preview.svg — compact SVG render. Read-only.POST /mcp initialize → server returns Mcp-Session-Id header.GET /mcp with Accept: text/event-stream + Mcp-Session-Id: <id> opens the SSE stream.POST /mcp resources/subscribe { uri: "cnvs://board/{id}/state.json" } with the same session id registers the subscription.notifications/resources/updated JSON-RPC messages onto the SSE stream ~3 s after every edit burst settles (debounced — one wake-up per burst, not per mutation).: SSE comment every 25 s keeps intermediaries from closing the stream.Durability: the debounce timer uses the Durable Object alarm API, so even if the DO is evicted between a mutation and the 3 s window the alarm still wakes it up. Subscriber lists are persisted in DO storage.
For AI agents that want to be a live collaborator on a board, the empirically fastest pattern is:
cnvs://board/<id>/state.json. The server pushes within ~3 s of every edit. This is the only way to get a push — REST has no webhook.POST /api/boards/<id>/{texts,strokes,images,links}. Simpler than threading through MCP tool calls; same validator/broadcast path server-side.mcp-listen skill's --ignore-author-prefix "ai:" suppresses notifications caused by any ai:* author so your own writes don't wake your own listener.Why hybrid beats pure-MCP: REST is universal (any HTTP client), avoids JSON-RPC bookkeeping, doesn't burn MCP tool-call slots. MCP push is the only real-time channel. Each plays to its strength.
Default: none. Board ID is the access credential. Optional 6-char PIN lock ([a-z0-9]{6}) with two modes:
mode: write — public read, key required for mutations.mode: all — key required for everything.Pass key via X-Board-Key HTTP header (REST + MCP POST) or access_key argument on individual tool calls. Locked-board responses: HTTP 401 {code: "board_locked", lockMode} for REST; JSON-RPC -32001 board_locked for MCP.
user:<uuid> (per-device, stable, in localStorage).ai:claude; override via author: "ai:<label>".ai:rest; same override.Charset [A-Za-z0-9:_\-.], max 80 chars. Immutable after creation. AI-authored items render with a purple border in the SVG preview.
-32000 payload_too_large.-32000 rate_limited./quotas.json.resources/list_changed notifications.