{
  "data": {
    "tool": {
      "category": "",
      "endpoint": "https://cnvs.app/mcp",
      "jsonUrl": "https://www.anchorterminal.com/api/v1/tools/cnvs-whiteboard.json",
      "kind": "mcp",
      "listed": "indexed",
      "liveUrl": "https://www.anchorterminal.com/api/v1/live/cnvs-whiteboard.json",
      "markdownUrl": "https://www.anchorterminal.com/tools/cnvs-whiteboard.md",
      "mcpTools": {
        "check": {
          "checker": "anchor-check/1.0",
          "totalTokens": 8632,
          "counts": {
            "error": 0,
            "note": 1,
            "warn": 26
          },
          "findings": [
            {
              "rule": "TC11",
              "severity": "warn",
              "tool": "add_image",
              "message": "9 parameters without a description: author, board_id, data_url, height, id, thumb_data_url and 3 more",
              "fix": "Describe each one: format, units, an example, and what happens when it's left out."
            },
            {
              "rule": "TC11",
              "severity": "warn",
              "tool": "add_link",
              "message": "5 parameters without a description: author, board_id, url, x, y",
              "fix": "Describe each one: format, units, an example, and what happens when it's left out."
            },
            {
              "rule": "TC11",
              "severity": "warn",
              "tool": "add_text",
              "message": "5 parameters without a description: board_id, content, postit, x, y",
              "fix": "Describe each one: format, units, an example, and what happens when it's left out."
            },
            {
              "rule": "TC11",
              "severity": "warn",
              "tool": "create_column",
              "message": "2 parameters without a description: board_id, title",
              "fix": "Describe each one: format, units, an example, and what happens when it's left out."
            },
            {
              "rule": "TC11",
              "severity": "warn",
              "tool": "create_task",
              "message": "5 parameters without a description: assignee, board_id, column_id, description, name",
              "fix": "Describe each one: format, units, an example, and what happens when it's left out."
            },
            {
              "rule": "TC11",
              "severity": "warn",
              "tool": "create_tasks",
              "message": "1 parameter without a description: board_id",
              "fix": "Describe each one: format, units, an example, and what happens when it's left out."
            },
            {
              "rule": "TC11",
              "severity": "warn",
              "tool": "delete_column",
              "message": "2 parameters without a description: board_id, id",
              "fix": "Describe each one: format, units, an example, and what happens when it's left out."
            },
            {
              "rule": "TC11",
              "severity": "warn",
              "tool": "delete_task",
              "message": "2 parameters without a description: board_id, id",
              "fix": "Describe each one: format, units, an example, and what happens when it's left out."
            },
            {
              "rule": "TC11",
              "severity": "warn",
              "tool": "draw_stroke",
              "message": "4 parameters without a description: author, board_id, color, id",
              "fix": "Describe each one: format, units, an example, and what happens when it's left out."
            },
            {
              "rule": "TC11",
              "severity": "warn",
              "tool": "erase",
              "message": "3 parameters without a description: board_id, id, kind",
              "fix": "Describe each one: format, units, an example, and what happens when it's left out."
            },
            {
              "rule": "TC11",
              "severity": "warn",
              "tool": "export_tasks",
              "message": "1 parameter without a description: board_id",
              "fix": "Describe each one: format, units, an example, and what happens when it's left out."
            },
            {
              "rule": "TC11",
              "severity": "warn",
              "tool": "get_board",
              "message": "1 parameter without a description: board_id",
              "fix": "Describe each one: format, units, an example, and what happens when it's left out."
            },
            {
              "rule": "TC11",
              "severity": "warn",
              "tool": "get_preview",
              "message": "1 parameter without a description: board_id",
              "fix": "Describe each one: format, units, an example, and what happens when it's left out."
            },
            {
              "rule": "TC11",
              "severity": "warn",
              "tool": "list_tasks",
              "message": "1 parameter without a description: board_id",
              "fix": "Describe each one: format, units, an example, and what happens when it's left out."
            },
            {
              "rule": "TC11",
              "severity": "warn",
              "tool": "move",
              "message": "4 parameters without a description: board_id, id, x, y",
              "fix": "Describe each one: format, units, an example, and what happens when it's left out."
            },
            {
              "rule": "TC11",
              "severity": "warn",
              "tool": "move_task",
              "message": "4 parameters without a description: board_id, column_id, id, sort",
              "fix": "Describe each one: format, units, an example, and what happens when it's left out."
            },
            {
              "rule": "TC11",
              "severity": "warn",
              "tool": "query_tasks",
              "message": "3 parameters without a description: board_id, done, priority",
              "fix": "Describe each one: format, units, an example, and what happens when it's left out."
            },
            {
              "rule": "TC11",
              "severity": "warn",
              "tool": "set_board_mode",
              "message": "1 parameter without a description: board_id",
              "fix": "Describe each one: format, units, an example, and what happens when it's left out."
            },
            {
              "rule": "TC11",
              "severity": "warn",
              "tool": "set_column_width",
              "message": "1 parameter without a description: board_id",
              "fix": "Describe each one: format, units, an example, and what happens when it's left out."
            },
            {
              "rule": "TC11",
              "severity": "warn",
              "tool": "set_lane",
              "message": "1 parameter without a description: board_id",
              "fix": "Describe each one: format, units, an example, and what happens when it's left out."
            },
            {
              "rule": "TC11",
              "severity": "warn",
              "tool": "update_column",
              "message": "3 parameters without a description: board_id, id, title",
              "fix": "Describe each one: format, units, an example, and what happens when it's left out."
            },
            {
              "rule": "TC11",
              "severity": "warn",
              "tool": "update_task",
              "message": "8 parameters without a description: assignee, board_id, column_id, description, id, name and 2 more",
              "fix": "Describe each one: format, units, an example, and what happens when it's left out."
            },
            {
              "rule": "TC11",
              "severity": "warn",
              "tool": "wait_for_update",
              "message": "2 parameters without a description: board_id, timeout_ms",
              "fix": "Describe each one: format, units, an example, and what happens when it's left out."
            },
            {
              "rule": "TC12",
              "severity": "warn",
              "tool": "draw_stroke",
              "message": "no type for points",
              "fix": "Give every parameter a type (or an enum)."
            },
            {
              "rule": "TC13",
              "severity": "warn",
              "tool": "create_board",
              "message": "content (object with no properties)",
              "fix": "Declare the properties (or additionalProperties with a schema) and the array's items."
            },
            {
              "rule": "TC18",
              "severity": "warn",
              "tool": "wait_for_update",
              "message": "readOnlyHint is true but the name says \"update\"",
              "fix": "If it changes anything, readOnlyHint must be false."
            },
            {
              "rule": "TC24",
              "severity": "note",
              "message": "25 of 25 tools have no outputSchema",
              "fix": "Declare outputSchema for tools that return structured data, and return structuredContent that matches it."
            }
          ]
        },
        "checkedAt": "2026-10-04T22:21:04Z",
        "count": 25,
        "note": "answered without the initialize handshake",
        "schemaTokens": 8632,
        "status": "ok",
        "tools": [
          {
            "name": "open_board",
            "title": "Open Board",
            "description": "ALWAYS call this first when given a board URL or ID. Resolves the canonical board id and auto-creates the board row if it does not exist yet. Returns a summary (item counts, authors). After this, call BOTH `get_preview` and `get_board` before editing so you can see the layout visually AND know the exact ids/coordinates — do not skip `get_preview`, otherwise you will place new items blindly on top of existing ones.",
            "inputSchema": {
              "properties": {
                "access_key": {
                  "description": "8-character lowercase alphanumeric board access key when the board is locked (legacy 6-character lowercase alphanumeric keys are also accepted). Equivalent to setting the `X-Board-Key` HTTP header on the JSON-RPC POST. Omit for unlocked boards. Obtain via POST /api/boards/\u003cid\u003e/lock.",
                  "type": "string"
                },
                "url_or_id": {
                  "description": "Full board URL (https://cnvs.app/#\u003cid\u003e) or bare UUID.",
                  "type": "string"
                }
              },
              "required": [
                "url_or_id"
              ],
              "type": "object"
            },
            "annotations": {
              "destructiveHint": false,
              "openWorldHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "create_board",
            "title": "Create Board",
            "description": "Create a fresh board in ONE call — optionally pre-filled with content, auto-laid-out, and/or PIN-locked at create time. Mirrors the extended `POST /api/boards` REST body exactly (same server-side implementation). With no arguments it returns a blank draw board; `mode: 'todo'` (+ optional `template`) seeds a kanban board. `content` imports initial items atomically: everything is validated FIRST and the board is created only if every item passes — on any invalid item you get a structured error naming its kind + index and NOTHING is created. `autolayout: true` (draw mode) fills in x/y for texts/images that omit them (deterministic masonry grid; explicit coordinates are never touched). `lock: 'write'|'all'` locks the board atomically with creation and returns the plaintext `access_key` ONCE — there is no recovery. The response's `imported` counts confirm what was created, `ids` returns the server-minted item ids per kind in the order you supplied them (index i of `ids.texts` is the id created for `content.texts[i]`; `ids.columns` is empty when the columns came from the template seed, and lanes have no id — they are keyed by board + lane index), and `embed_url` (the `?embed=1#\u003cid\u003e` iframe view) is returned for any board readable without a key — it is omitted for `lock:'all'` boards, whose embed frame can't read the board anonymously. Prefer this over open_board + N per-item calls when you are building a whole board from scratch.",
            "inputSchema": {
              "properties": {
                "author": {
                  "description": "Author tag stamped on every created item (e.g. 'ai:plai'). Defaults to 'ai:import'.",
                  "type": "string"
                },
                "autolayout": {
                  "description": "Draw mode only: fill x/y for texts/images that omit them (deterministic masonry). Without it, items missing coordinates are rejected. No-op in todo mode.",
                  "type": "boolean"
                },
                "content": {
                  "description": "Initial board content, applied atomically at create time. Draw mode: `texts` [{x?, y?, content, color?, width?, postit?, diagram?, kind?, author?, sourceId?}], `lines` [{points, color?, anchors?, author?}] (alias `strokes`), `images` [{x?, y?, dataUrl, width, height, author?, sourceId?}]. Todo mode: `columns` [{title, lane?, color?, author?}] (array order = sort order), `tasks` [{columnIndex, name, description?, due_date?, priority?, assignee?, done?, color?, author?}] (columnIndex indexes into content.columns, or into the template-seeded columns when content.columns is empty), `lanes` [{lane, title, author?}], `colWidth`. Every item's optional `author` is its CREATOR tag (same 1-80 char [A-Za-z0-9:_-.] rule as elsewhere) and is never rewritten later — omit it to inherit the top-level `author`, or set it per item to preserve the original authorship when restoring somebody else's board. Item ids are ALWAYS minted server-side and returned in `ids`; you cannot choose them. To keep anchored strokes, give a text/image an optional `sourceId` (unique string, \u003c=128 chars, write-only — never stored, never the row id) and reference it from `lines[].anchors.start.id` / `.end.id`: matching ids are rewritten to the minted id, unmatched ids are left as-is and render as a free stroke end. Kanban structures with a non-todo mode (or draw items with mode 'todo') are rejected with `content_mode_mismatch`. The combined input arrays may contain at most 2550 entries. At most 10 lane-title entries are accepted, every title must reference a lane used by a created column, and each lane index may be named AT MOST ONCE — a second entry for the same lane is rejected (naming that second entry's index) instead of collapsing last-write-wins, which would overwrite the first entry's author. `tasks[].done` must be a real boolean (or omitted/null for not-done): a truthy stand-in such as the string \"false\" is rejected rather than coerced, so a card is never imported as completed by accident. Standard per-board quotas also apply, and the 5 MB request-body cap is the real ceiling for image-heavy imports. A valid X-Import-Token selects higher REST/MCP and board-create rate tiers, but never changes these content limits.",
                  "type": "object"
                },
                "lock": {
                  "description": "PIN-lock the board atomically at create time; the plaintext key is returned ONCE as `access_key`.",
                  "enum": [
                    "write",
                    "all"
                  ],
                  "type": "string"
                },
                "mode": {
                  "description": "Board mode. Defaults to 'draw'.",
                  "enum": [
                    "draw",
                    "todo"
                  ],
                  "type": "string"
                },
                "template": {
                  "description": "Starter column set when mode is 'todo' and content.columns is empty/absent. Defaults to 'kanban'.",
                  "enum": [
                    "kanban",
                    "sprint",
                    "bugs"
                  ],
                  "type": "string"
                }
              },
              "type": "object"
            },
            "annotations": {
              "destructiveHint": false,
              "openWorldHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "get_board",
            "title": "Get Board",
            "description": "Full structured JSON state of a board: texts (id, x, y, content, color, width, postit, author), strokes (id, points, color, author), images (id, x, y, width, height, dataUrl, thumbDataUrl, author; heavy base64 \u003e8 kB elided to dataUrl:null, tiny images inlined). Use this for EXACT ids/coordinates/content (needed for `move`, `erase`, editing a text by id). For visual layout (where is empty space? what overlaps?) call `get_preview` instead — it's much cheaper for spatial reasoning than a huge JSON dump.",
            "inputSchema": {
              "properties": {
                "access_key": {
                  "description": "8-character lowercase alphanumeric board access key when the board is locked (legacy 6-character lowercase alphanumeric keys are also accepted). Equivalent to setting the `X-Board-Key` HTTP header on the JSON-RPC POST. Omit for unlocked boards. Obtain via POST /api/boards/\u003cid\u003e/lock.",
                  "type": "string"
                },
                "board_id": {
                  "type": "string"
                }
              },
              "required": [
                "board_id"
              ],
              "type": "object"
            },
            "annotations": {
              "destructiveHint": false,
              "openWorldHint": false,
              "readOnlyHint": false
            }
          },
          {
            "name": "get_preview",
            "title": "Get Board Preview",
            "description": "Compact schematic SVG render of the board (typically a few kB even for dense boards). Returns both an image/svg+xml content block (you can SEE it) and the raw SVG text. CALL THIS any time you need to understand where things are — before placing new items, before deciding whether the canvas is crowded, before picking a free region. AI-authored items get a purple border so you can tell which contributions were yours. For precise text content prefer `get_board`.",
            "inputSchema": {
              "properties": {
                "access_key": {
                  "description": "8-character lowercase alphanumeric board access key when the board is locked (legacy 6-character lowercase alphanumeric keys are also accepted). Equivalent to setting the `X-Board-Key` HTTP header on the JSON-RPC POST. Omit for unlocked boards. Obtain via POST /api/boards/\u003cid\u003e/lock.",
                  "type": "string"
                },
                "board_id": {
                  "type": "string"
                }
              },
              "required": [
                "board_id"
              ],
              "type": "object"
            },
            "annotations": {
              "destructiveHint": false,
              "openWorldHint": false,
              "readOnlyHint": true
            }
          },
          {
            "name": "add_text",
            "title": "Add Text",
            "description": "Create a NEW text node, or update an existing one (pass the same `id` to overwrite content/position in place — preferred over creating a duplicate). Supports cnvs markup (Markdown-ish) and Mermaid diagrams in the content. When using Mermaid, the ENTIRE content of this text node must be a single Mermaid diagram (one ```mermaid fenced block and nothing else — no heading, no prose before or after). If you need prose + a diagram, create two separate text nodes. `postit: true` renders as a yellow sticky; `diagram: true` renders as a framed box (2px border in the text colour, centred text) — the two are mutually exclusive. Coordinates are in board-world pixels, +x right, +y DOWN; pick a spot that does not overlap existing items (check `get_preview` first). Default width auto-fits content up to ~320 px; pass `width` for explicit wrapping (160–4096). Keep content under 100 000 chars.",
            "inputSchema": {
              "properties": {
                "access_key": {
                  "description": "8-character lowercase alphanumeric board access key when the board is locked (legacy 6-character lowercase alphanumeric keys are also accepted). Equivalent to setting the `X-Board-Key` HTTP header on the JSON-RPC POST. Omit for unlocked boards. Obtain via POST /api/boards/\u003cid\u003e/lock.",
                  "type": "string"
                },
                "author": {
                  "description": "Author tag, defaults to ai:claude.",
                  "type": "string"
                },
                "board_id": {
                  "type": "string"
                },
                "color": {
                  "description": "Named ink only (no hex). Accepted (case-insensitive): 'auto'/''/'black'/omitted for theme-aware ink, or 'red', 'blue', 'green', 'orange', 'yellow', 'pink', 'purple', 'maroon', 'brown', 'gray', 'lightgray', 'teal', 'sage', 'sky', 'lavender'. Anything else (including a literal hex) silently clamps to auto.",
                  "type": "string"
                },
                "content": {
                  "type": "string"
                },
                "diagram": {
                  "description": "Render as a framed diagram box (2px border in the text colour, centred text). Mutually exclusive with postit.",
                  "type": "boolean"
                },
                "id": {
                  "description": "Optional stable id; generated when omitted.",
                  "type": "string"
                },
                "postit": {
                  "type": "boolean"
                },
                "width": {
                  "description": "Explicit width in px (160–4096).",
                  "type": "number"
                },
                "x": {
                  "type": "number"
                },
                "y": {
                  "type": "number"
                }
              },
              "required": [
                "board_id",
                "x",
                "y",
                "content"
              ],
              "type": "object"
            },
            "annotations": {
              "destructiveHint": true,
              "openWorldHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "add_link",
            "title": "Add Link",
            "description": "Drop a URL capsule onto the board — rendered as a clickable pill showing the hostname. Use this instead of `add_text` when the node is just a link; the capsule styling signals clickability to humans. Same coordinate rules as `add_text` (+x right, +y down).",
            "inputSchema": {
              "properties": {
                "access_key": {
                  "description": "8-character lowercase alphanumeric board access key when the board is locked (legacy 6-character lowercase alphanumeric keys are also accepted). Equivalent to setting the `X-Board-Key` HTTP header on the JSON-RPC POST. Omit for unlocked boards. Obtain via POST /api/boards/\u003cid\u003e/lock.",
                  "type": "string"
                },
                "author": {
                  "type": "string"
                },
                "board_id": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "x": {
                  "type": "number"
                },
                "y": {
                  "type": "number"
                }
              },
              "required": [
                "board_id",
                "x",
                "y",
                "url"
              ],
              "type": "object"
            },
            "annotations": {
              "destructiveHint": false,
              "openWorldHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "add_image",
            "title": "Add Image",
            "description": "Place a raster or SVG image on the board at (x, y) with explicit width/height in board pixels. `data_url` MUST be a `data:image/(png|jpeg|gif|webp|svg+xml);base64,...` string ≤ ~900 kB; hosted URLs are not accepted. Strongly recommended: also pass a tiny `thumb_data_url` (≤8 kB JPEG/PNG/WebP, ~64 px on the long edge) — it is embedded into the SVG preview so OTHER AI viewers (and you, on later `get_preview` calls) can actually see the image instead of a placeholder box.",
            "inputSchema": {
              "properties": {
                "access_key": {
                  "description": "8-character lowercase alphanumeric board access key when the board is locked (legacy 6-character lowercase alphanumeric keys are also accepted). Equivalent to setting the `X-Board-Key` HTTP header on the JSON-RPC POST. Omit for unlocked boards. Obtain via POST /api/boards/\u003cid\u003e/lock.",
                  "type": "string"
                },
                "author": {
                  "type": "string"
                },
                "board_id": {
                  "type": "string"
                },
                "data_url": {
                  "type": "string"
                },
                "height": {
                  "type": "number"
                },
                "id": {
                  "type": "string"
                },
                "thumb_data_url": {
                  "type": "string"
                },
                "width": {
                  "type": "number"
                },
                "x": {
                  "type": "number"
                },
                "y": {
                  "type": "number"
                }
              },
              "required": [
                "board_id",
                "x",
                "y",
                "width",
                "height",
                "data_url"
              ],
              "type": "object"
            },
            "annotations": {
              "destructiveHint": true,
              "openWorldHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "draw_stroke",
            "title": "Draw Stroke",
            "description": "Draw a freehand stroke on the board. Use for arrows, underlines, connector lines, annotations, or simple shapes — a straight line needs two points, a rough circle wants ~20. Stroke width is fixed at 3 px; `color` is a NAME, not hex (case-insensitive): 'auto'/''/'black'/omitted for theme-aware ink, or 'red', 'blue', 'green', 'orange', 'yellow', 'pink', 'purple', 'maroon', 'brown', 'gray', 'lightgray', 'teal', 'sage', 'sky', 'lavender' — anything else (including a literal hex like '#ff0000') silently clamps to auto. Accepts three equivalent point formats — pick whichever your MCP client serialises cleanly: nested `[[x,y],[x,y],...]`, flat `[x1,y1,x2,y2,...]`, or a JSON string of either. Some clients (Claude Code as of 2026-04) drop nested arrays during tool-call serialisation, so prefer the flat form or the JSON-string form when in doubt. To delete a stroke later, use `erase` with `kind: 'line'` and the id returned here.",
            "inputSchema": {
              "properties": {
                "access_key": {
                  "description": "8-character lowercase alphanumeric board access key when the board is locked (legacy 6-character lowercase alphanumeric keys are also accepted). Equivalent to setting the `X-Board-Key` HTTP header on the JSON-RPC POST. Omit for unlocked boards. Obtain via POST /api/boards/\u003cid\u003e/lock.",
                  "type": "string"
                },
                "author": {
                  "type": "string"
                },
                "board_id": {
                  "type": "string"
                },
                "color": {
                  "type": "string"
                },
                "id": {
                  "type": "string"
                },
                "points": {
                  "description": "Points as [[x,y],...], flat [x1,y1,x2,y2,...], or a JSON string of either."
                }
              },
              "required": [
                "board_id",
                "points"
              ],
              "type": "object"
            },
            "annotations": {
              "destructiveHint": true,
              "openWorldHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "move",
            "title": "Move Item",
            "description": "Reposition an existing item to a new (x, y) without retyping its content. Works for every item kind: `text` and `link` set the top-left to (x, y); `line` translates every point so the stroke's bounding box top-left lands at (x, y); `image` sets the top-left like text. `kind` defaults to `text` for backward compat with older callers. Find the id + kind via `get_board`. Prefer `move` over re-creating an item when only the location changes — it preserves the id, content, author and avoids a round-trip of base64 bytes for images.",
            "inputSchema": {
              "properties": {
                "access_key": {
                  "description": "8-character lowercase alphanumeric board access key when the board is locked (legacy 6-character lowercase alphanumeric keys are also accepted). Equivalent to setting the `X-Board-Key` HTTP header on the JSON-RPC POST. Omit for unlocked boards. Obtain via POST /api/boards/\u003cid\u003e/lock.",
                  "type": "string"
                },
                "board_id": {
                  "type": "string"
                },
                "id": {
                  "type": "string"
                },
                "kind": {
                  "description": "Item kind. Defaults to `text`.",
                  "enum": [
                    "text",
                    "link",
                    "line",
                    "image"
                  ],
                  "type": "string"
                },
                "x": {
                  "type": "number"
                },
                "y": {
                  "type": "number"
                }
              },
              "required": [
                "board_id",
                "id",
                "x",
                "y"
              ],
              "type": "object"
            },
            "annotations": {
              "destructiveHint": false,
              "openWorldHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "erase",
            "title": "Erase Item",
            "description": "Delete a single item by id. `kind` MUST match the item type: 'text' for text nodes, 'line' for freehand strokes, 'image' for images — the wrong kind silently targets the wrong table and is a common mistake. Get the id + type from `get_board` (texts[], lines[], images[]). There is no bulk/erase-all tool: loop if you need to delete multiple items.",
            "inputSchema": {
              "properties": {
                "access_key": {
                  "description": "8-character lowercase alphanumeric board access key when the board is locked (legacy 6-character lowercase alphanumeric keys are also accepted). Equivalent to setting the `X-Board-Key` HTTP header on the JSON-RPC POST. Omit for unlocked boards. Obtain via POST /api/boards/\u003cid\u003e/lock.",
                  "type": "string"
                },
                "board_id": {
                  "type": "string"
                },
                "id": {
                  "type": "string"
                },
                "kind": {
                  "enum": [
                    "text",
                    "line",
                    "image"
                  ],
                  "type": "string"
                }
              },
              "required": [
                "board_id",
                "id",
                "kind"
              ],
              "type": "object"
            },
            "annotations": {
              "destructiveHint": true,
              "openWorldHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "wait_for_update",
            "title": "Wait for Board Update",
            "description": "Long-poll: blocks until the next edit lands on this board, then returns. \n\nWHEN TO CALL THIS: if your MCP client does NOT surface `notifications/resources/updated` events from `resources/subscribe` back to the model (most chat clients do not — they receive the SSE event but don't inject it into your context), this tool is how you 'wait for the human' inside a single turn. Typical flow: you draw / write what you were asked to, then instead of ending your turn you call `wait_for_update(board_id)`. When the human adds, moves, or erases something, the call returns and you refresh with `get_preview` / `get_board` and continue the collaboration. Great for turn-based interactions (games like tic-tac-toe, brainstorming where you respond to each sticky the user drops, sketch-and-feedback loops, etc.). If your client DOES deliver resource notifications natively, prefer `resources/subscribe` — it's cheaper and has no timeout ceiling.\n\nBEHAVIOUR: resolves ~3 s after the edit burst settles (same debounce as the push notifications — this is intentional so drags and long strokes collapse into one wake-up). Returns `{ updated: true, timedOut: false }` on a real edit, or `{ updated: false, timedOut: true }` if nothing happened within `timeout_ms`. On timeout, just call it again to keep waiting; chaining calls is cheap. `timeout_ms` is clamped to [1000, 55000]; default 25000 (leaves headroom under typical 60 s proxy timeouts).",
            "inputSchema": {
              "properties": {
                "access_key": {
                  "description": "8-character lowercase alphanumeric board access key when the board is locked (legacy 6-character lowercase alphanumeric keys are also accepted). Equivalent to setting the `X-Board-Key` HTTP header on the JSON-RPC POST. Omit for unlocked boards. Obtain via POST /api/boards/\u003cid\u003e/lock.",
                  "type": "string"
                },
                "board_id": {
                  "type": "string"
                },
                "timeout_ms": {
                  "type": "number"
                }
              },
              "required": [
                "board_id"
              ],
              "type": "object"
            },
            "annotations": {
              "destructiveHint": false,
              "openWorldHint": false,
              "readOnlyHint": true
            }
          },
          {
            "name": "set_board_mode",
            "title": "Set Board Mode",
            "description": "Choose whether this board is a freeform whiteboard ('draw', the default) or a kanban task board ('todo'). Mode is switchable WHENEVER the board is empty of real content: drawings (text/strokes/images) and tasks. Empty or seeded columns DON'T count (switching to 'draw' clears them), so a cleared board can be switched again, and you can flip draw\u003c-\u003etodo freely until the first stroke/text/image or task lands. Setting 'todo' auto-seeds three starter columns (To do / In progress / Done). Returns `{ mode, columns }`. Use the task/column tools (`create_task`, `create_column`, …) once the board is in 'todo' mode.",
            "inputSchema": {
              "properties": {
                "access_key": {
                  "description": "8-character lowercase alphanumeric board access key when the board is locked (legacy 6-character lowercase alphanumeric keys are also accepted). Equivalent to setting the `X-Board-Key` HTTP header on the JSON-RPC POST. Omit for unlocked boards. Obtain via POST /api/boards/\u003cid\u003e/lock.",
                  "type": "string"
                },
                "board_id": {
                  "type": "string"
                },
                "mode": {
                  "description": "Board mode.",
                  "enum": [
                    "draw",
                    "todo"
                  ],
                  "type": "string"
                },
                "template": {
                  "description": "Optional starter column template when mode is 'todo': 'kanban' (To do / In progress / Done, the default), 'sprint' (Backlog / Sprint / Review / Done), or 'bugs' (Triage / Confirmed / In progress / Fixed). Unknown/omitted falls back to 'kanban'.",
                  "type": "string"
                }
              },
              "required": [
                "board_id",
                "mode"
              ],
              "type": "object"
            },
            "annotations": {
              "destructiveHint": true,
              "openWorldHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "create_column",
            "title": "Create Column",
            "description": "Add a kanban column (swimlane) to a 'todo' board. Generates and returns a stable column id. `sort` is a float ordering key (ascending); omit to default to 0. `lane` is an integer row index for multi-row layouts (defaults to 0). `color` is an optional title color ('red' / 'blue' / 'green', or 'auto' / omit for default). To rename, reorder, recolor or move between lanes later use `update_column`.",
            "inputSchema": {
              "properties": {
                "access_key": {
                  "description": "8-character lowercase alphanumeric board access key when the board is locked (legacy 6-character lowercase alphanumeric keys are also accepted). Equivalent to setting the `X-Board-Key` HTTP header on the JSON-RPC POST. Omit for unlocked boards. Obtain via POST /api/boards/\u003cid\u003e/lock.",
                  "type": "string"
                },
                "author": {
                  "description": "Author tag, defaults to ai:claude.",
                  "type": "string"
                },
                "board_id": {
                  "type": "string"
                },
                "color": {
                  "description": "Title color: 'red', 'blue', 'green', or 'auto' (default).",
                  "type": "string"
                },
                "lane": {
                  "description": "Row index for multi-row layouts. Defaults to 0.",
                  "type": "integer"
                },
                "sort": {
                  "description": "Float ordering key (ascending). Defaults to 0.",
                  "type": "number"
                },
                "title": {
                  "type": "string"
                }
              },
              "required": [
                "board_id",
                "title"
              ],
              "type": "object"
            },
            "annotations": {
              "destructiveHint": false,
              "openWorldHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "update_column",
            "title": "Update Column",
            "description": "Rename, reorder, recolor or move an existing kanban column. Requires the column `id` (from `list_tasks`). Pass `title`, `sort`, `lane` and/or `color` to change them.",
            "inputSchema": {
              "properties": {
                "access_key": {
                  "description": "8-character lowercase alphanumeric board access key when the board is locked (legacy 6-character lowercase alphanumeric keys are also accepted). Equivalent to setting the `X-Board-Key` HTTP header on the JSON-RPC POST. Omit for unlocked boards. Obtain via POST /api/boards/\u003cid\u003e/lock.",
                  "type": "string"
                },
                "author": {
                  "description": "Author tag, defaults to ai:claude.",
                  "type": "string"
                },
                "board_id": {
                  "type": "string"
                },
                "color": {
                  "description": "Title color: 'red', 'blue', 'green', or 'auto' (default).",
                  "type": "string"
                },
                "id": {
                  "type": "string"
                },
                "lane": {
                  "description": "Row index for multi-row layouts.",
                  "type": "integer"
                },
                "sort": {
                  "description": "Float ordering key (ascending).",
                  "type": "number"
                },
                "title": {
                  "type": "string"
                }
              },
              "required": [
                "board_id",
                "id"
              ],
              "type": "object"
            },
            "annotations": {
              "destructiveHint": true,
              "openWorldHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "delete_column",
            "title": "Delete Column",
            "description": "Delete a kanban column by id. Tasks in the column are removed with it. Get the id from `list_tasks`.",
            "inputSchema": {
              "properties": {
                "access_key": {
                  "description": "8-character lowercase alphanumeric board access key when the board is locked (legacy 6-character lowercase alphanumeric keys are also accepted). Equivalent to setting the `X-Board-Key` HTTP header on the JSON-RPC POST. Omit for unlocked boards. Obtain via POST /api/boards/\u003cid\u003e/lock.",
                  "type": "string"
                },
                "board_id": {
                  "type": "string"
                },
                "id": {
                  "type": "string"
                }
              },
              "required": [
                "board_id",
                "id"
              ],
              "type": "object"
            },
            "annotations": {
              "destructiveHint": true,
              "openWorldHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "create_task",
            "title": "Create Task",
            "description": "Create a task (card) in a column on a 'todo' board. Generates and returns a stable task id. `column_id` must reference an existing column (see `list_tasks`). `description` is free-form prose stored on the card; `priority` is one of 'H' | 'M' | 'L' (omit for none); `due_date` is an ISO 8601 date string; `assignee` is free text (name / initials / email). `sort` is a float ordering key within the column (ascending), defaulting to 0.",
            "inputSchema": {
              "properties": {
                "access_key": {
                  "description": "8-character lowercase alphanumeric board access key when the board is locked (legacy 6-character lowercase alphanumeric keys are also accepted). Equivalent to setting the `X-Board-Key` HTTP header on the JSON-RPC POST. Omit for unlocked boards. Obtain via POST /api/boards/\u003cid\u003e/lock.",
                  "type": "string"
                },
                "assignee": {
                  "type": "string"
                },
                "author": {
                  "description": "Author tag, defaults to ai:claude.",
                  "type": "string"
                },
                "board_id": {
                  "type": "string"
                },
                "column_id": {
                  "type": "string"
                },
                "description": {
                  "type": "string"
                },
                "done": {
                  "description": "Whether the task is completed (checked off). Defaults to false.",
                  "type": "boolean"
                },
                "due_date": {
                  "description": "ISO 8601 date.",
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "priority": {
                  "description": "High / Medium / Low. Omit for none.",
                  "enum": [
                    "H",
                    "M",
                    "L"
                  ],
                  "type": "string"
                },
                "sort": {
                  "description": "Float ordering key within the column. Defaults to 0.",
                  "type": "number"
                }
              },
              "required": [
                "board_id",
                "column_id",
                "name"
              ],
              "type": "object"
            },
            "annotations": {
              "destructiveHint": false,
              "openWorldHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "update_task",
            "title": "Update Task",
            "description": "Update an existing task by `id` (from `list_tasks`). Pass only the fields you want to change: `name`, `description`, `due_date`, `priority` ('H'|'M'|'L'), `assignee`, `done` (true once completed), `column_id` (to reassign), `sort`. To move a card between columns while setting its order, `move_task` is the dedicated tool.",
            "inputSchema": {
              "properties": {
                "access_key": {
                  "description": "8-character lowercase alphanumeric board access key when the board is locked (legacy 6-character lowercase alphanumeric keys are also accepted). Equivalent to setting the `X-Board-Key` HTTP header on the JSON-RPC POST. Omit for unlocked boards. Obtain via POST /api/boards/\u003cid\u003e/lock.",
                  "type": "string"
                },
                "assignee": {
                  "type": "string"
                },
                "author": {
                  "description": "Author tag, defaults to ai:claude.",
                  "type": "string"
                },
                "board_id": {
                  "type": "string"
                },
                "column_id": {
                  "type": "string"
                },
                "description": {
                  "type": "string"
                },
                "done": {
                  "description": "Whether the task is completed (checked off).",
                  "type": "boolean"
                },
                "due_date": {
                  "description": "ISO 8601 date.",
                  "type": "string"
                },
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "priority": {
                  "enum": [
                    "H",
                    "M",
                    "L"
                  ],
                  "type": "string"
                },
                "sort": {
                  "type": "number"
                }
              },
              "required": [
                "board_id",
                "id"
              ],
              "type": "object"
            },
            "annotations": {
              "destructiveHint": true,
              "openWorldHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "move_task",
            "title": "Move Task",
            "description": "Move a task to a column at a given sort position — the kanban drag-and-drop primitive. `column_id` is the destination column and `sort` its float order key (ascending) within that column.",
            "inputSchema": {
              "properties": {
                "access_key": {
                  "description": "8-character lowercase alphanumeric board access key when the board is locked (legacy 6-character lowercase alphanumeric keys are also accepted). Equivalent to setting the `X-Board-Key` HTTP header on the JSON-RPC POST. Omit for unlocked boards. Obtain via POST /api/boards/\u003cid\u003e/lock.",
                  "type": "string"
                },
                "board_id": {
                  "type": "string"
                },
                "column_id": {
                  "type": "string"
                },
                "id": {
                  "type": "string"
                },
                "sort": {
                  "type": "number"
                }
              },
              "required": [
                "board_id",
                "id",
                "column_id",
                "sort"
              ],
              "type": "object"
            },
            "annotations": {
              "destructiveHint": false,
              "openWorldHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "delete_task",
            "title": "Delete Task",
            "description": "Delete a task (card) by id. Get the id from `list_tasks`.",
            "inputSchema": {
              "properties": {
                "access_key": {
                  "description": "8-character lowercase alphanumeric board access key when the board is locked (legacy 6-character lowercase alphanumeric keys are also accepted). Equivalent to setting the `X-Board-Key` HTTP header on the JSON-RPC POST. Omit for unlocked boards. Obtain via POST /api/boards/\u003cid\u003e/lock.",
                  "type": "string"
                },
                "board_id": {
                  "type": "string"
                },
                "id": {
                  "type": "string"
                }
              },
              "required": [
                "board_id",
                "id"
              ],
              "type": "object"
            },
            "annotations": {
              "destructiveHint": true,
              "openWorldHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "list_tasks",
            "title": "List Tasks",
            "description": "Read the full kanban state of a 'todo' board: `{ mode, columns, tasks }`, both ordered by their `sort` key (ascending). Each task carries its hot fields (name, due_date, priority, assignee, done, column_id, sort) plus an opaque `content` JSON string (holds the description). Use this to get exact column/task ids before updating, moving or deleting.",
            "inputSchema": {
              "properties": {
                "access_key": {
                  "description": "8-character lowercase alphanumeric board access key when the board is locked (legacy 6-character lowercase alphanumeric keys are also accepted). Equivalent to setting the `X-Board-Key` HTTP header on the JSON-RPC POST. Omit for unlocked boards. Obtain via POST /api/boards/\u003cid\u003e/lock.",
                  "type": "string"
                },
                "board_id": {
                  "type": "string"
                }
              },
              "required": [
                "board_id"
              ],
              "type": "object"
            },
            "annotations": {
              "destructiveHint": false,
              "openWorldHint": false,
              "readOnlyHint": true
            }
          },
          {
            "name": "set_lane",
            "title": "Set Lane",
            "description": "Set (or clear) the title of a kanban row (lane). Lanes group columns into horizontal swimlanes; a lane is identified by its integer `lane` index (the same index columns carry). Pass a `title` to name the row, or an empty string to clear it. Read current lane titles + the shared column width via `list_tasks`.",
            "inputSchema": {
              "properties": {
                "access_key": {
                  "description": "8-character lowercase alphanumeric board access key when the board is locked (legacy 6-character lowercase alphanumeric keys are also accepted). Equivalent to setting the `X-Board-Key` HTTP header on the JSON-RPC POST. Omit for unlocked boards. Obtain via POST /api/boards/\u003cid\u003e/lock.",
                  "type": "string"
                },
                "author": {
                  "description": "Author tag, defaults to ai:claude.",
                  "type": "string"
                },
                "board_id": {
                  "type": "string"
                },
                "lane": {
                  "description": "Row index (\u003e= 0).",
                  "type": "integer"
                },
                "title": {
                  "description": "Row title; empty string clears it.",
                  "type": "string"
                }
              },
              "required": [
                "board_id",
                "lane"
              ],
              "type": "object"
            },
            "annotations": {
              "destructiveHint": true,
              "openWorldHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "set_column_width",
            "title": "Set Column Width",
            "description": "Set the shared kanban column width in pixels for a 'todo' board (all columns share one width). Clamped to [200, 480]. Read the current value as `colWidth` from `list_tasks`.",
            "inputSchema": {
              "properties": {
                "access_key": {
                  "description": "8-character lowercase alphanumeric board access key when the board is locked (legacy 6-character lowercase alphanumeric keys are also accepted). Equivalent to setting the `X-Board-Key` HTTP header on the JSON-RPC POST. Omit for unlocked boards. Obtain via POST /api/boards/\u003cid\u003e/lock.",
                  "type": "string"
                },
                "board_id": {
                  "type": "string"
                },
                "width": {
                  "description": "Column width in px, clamped to [200, 480].",
                  "type": "number"
                }
              },
              "required": [
                "board_id",
                "width"
              ],
              "type": "object"
            },
            "annotations": {
              "destructiveHint": false,
              "openWorldHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "create_tasks",
            "title": "Create Tasks",
            "description": "Bulk-create multiple task cards in one call — far cheaper than calling `create_task` N times. Pass `tasks`: an array of task objects, each with `column_id` (required) + the same fields `create_task` accepts (`name`, `description`, `due_date`, `priority`, `assignee`, `done`, `sort`). Returns the array of created ids in order. Stops at the first invalid item and reports its index; items before it are still created (not transactional).",
            "inputSchema": {
              "properties": {
                "access_key": {
                  "description": "8-character lowercase alphanumeric board access key when the board is locked (legacy 6-character lowercase alphanumeric keys are also accepted). Equivalent to setting the `X-Board-Key` HTTP header on the JSON-RPC POST. Omit for unlocked boards. Obtain via POST /api/boards/\u003cid\u003e/lock.",
                  "type": "string"
                },
                "author": {
                  "description": "Author tag applied to every task, defaults to ai:claude.",
                  "type": "string"
                },
                "board_id": {
                  "type": "string"
                },
                "tasks": {
                  "description": "Array of task objects to create.",
                  "items": {
                    "properties": {
                      "assignee": {
                        "type": "string"
                      },
                      "column_id": {
                        "type": "string"
                      },
                      "description": {
                        "type": "string"
                      },
                      "done": {
                        "type": "boolean"
                      },
                      "due_date": {
                        "description": "ISO 8601 date.",
                        "type": "string"
                      },
                      "name": {
                        "type": "string"
                      },
                      "priority": {
                        "enum": [
                          "H",
                          "M",
                          "L"
                        ],
                        "type": "string"
                      },
                      "sort": {
                        "type": "number"
                      }
                    },
                    "required": [
                      "column_id",
                      "name"
                    ],
                    "type": "object"
                  },
                  "type": "array"
                }
              },
              "required": [
                "board_id",
                "tasks"
              ],
              "type": "object"
            },
            "annotations": {
              "destructiveHint": false,
              "openWorldHint": true,
              "readOnlyHint": false
            }
          },
          {
            "name": "query_tasks",
            "title": "Query Tasks",
            "description": "Read tasks from a 'todo' board with server-side filtering — handy for 'what's overdue?' / 'what's assigned to X?' without pulling the whole board. All filters are optional and AND together: `assignee` (exact match), `priority` ('H'|'M'|'L'), `done` (boolean), `overdue` (true → due_date strictly before today, not done), `due_before` / `due_after` (ISO date window on due_date). Returns `{ boardId, mode, tasks }` — tasks ordered by sort, each with the same fields as `list_tasks`.",
            "inputSchema": {
              "properties": {
                "access_key": {
                  "description": "8-character lowercase alphanumeric board access key when the board is locked (legacy 6-character lowercase alphanumeric keys are also accepted). Equivalent to setting the `X-Board-Key` HTTP header on the JSON-RPC POST. Omit for unlocked boards. Obtain via POST /api/boards/\u003cid\u003e/lock.",
                  "type": "string"
                },
                "assignee": {
                  "description": "Exact-match assignee filter.",
                  "type": "string"
                },
                "board_id": {
                  "type": "string"
                },
                "done": {
                  "type": "boolean"
                },
                "due_after": {
                  "description": "ISO date; due_date \u003e this.",
                  "type": "string"
                },
                "due_before": {
                  "description": "ISO date; due_date \u003c this.",
                  "type": "string"
                },
                "overdue": {
                  "description": "Only tasks past due and not done.",
                  "type": "boolean"
                },
                "priority": {
                  "enum": [
                    "H",
                    "M",
                    "L"
                  ],
                  "type": "string"
                }
              },
              "required": [
                "board_id"
              ],
              "type": "object"
            },
            "annotations": {
              "destructiveHint": false,
              "openWorldHint": false,
              "readOnlyHint": true
            }
          },
          {
            "name": "export_tasks",
            "title": "Export Tasks",
            "description": "Export a 'todo' board's columns + tasks as a single text document. `format` is 'markdown' (a checklist grouped by column, the default) or 'csv' (one row per task with column/name/priority/assignee/due_date/done). Returns the rendered text. Same data as the GET /api/boards/\u003cid\u003e/tasks.md and tasks.csv REST endpoints.",
            "inputSchema": {
              "properties": {
                "access_key": {
                  "description": "8-character lowercase alphanumeric board access key when the board is locked (legacy 6-character lowercase alphanumeric keys are also accepted). Equivalent to setting the `X-Board-Key` HTTP header on the JSON-RPC POST. Omit for unlocked boards. Obtain via POST /api/boards/\u003cid\u003e/lock.",
                  "type": "string"
                },
                "board_id": {
                  "type": "string"
                },
                "format": {
                  "description": "Output format. Defaults to 'markdown'.",
                  "enum": [
                    "markdown",
                    "csv"
                  ],
                  "type": "string"
                }
              },
              "required": [
                "board_id"
              ],
              "type": "object"
            },
            "annotations": {
              "destructiveHint": false,
              "openWorldHint": false,
              "readOnlyHint": true
            }
          }
        ]
      },
      "name": "cnvs.app",
      "note": "Indexed from the official MCP registry: facts and our own checks, not reviewed, so no score, grade or rank.",
      "packages": null,
      "pageJsonUrl": "https://www.anchorterminal.com/tools/cnvs-whiteboard.json",
      "popularity": {
        "githubStars": 1
      },
      "registryName": "app.cnvs/whiteboard",
      "remotes": [
        {
          "type": "streamable-http",
          "url": "https://cnvs.app/mcp"
        }
      ],
      "repository": "https://github.com/lksrz/cnvs-whiteboard-skills",
      "reviewed": false,
      "slug": "cnvs-whiteboard",
      "source": "the official MCP registry",
      "sourceUrl": "https://registry.modelcontextprotocol.io/v0.1/servers?search=app.cnvs/whiteboard",
      "summary": "Real-time collaborative whiteboard — AI agents and humans edit the same board live over MCP.",
      "updatedAt": "2026-06-15T18:01:23Z",
      "url": "https://www.anchorterminal.com/tools/cnvs-whiteboard",
      "vendor": "cnvs.app",
      "vendorUrl": "https://cnvs.app",
      "version": "1.0.2",
      "websiteUrl": "https://cnvs.app",
      "where": "hosted",
      "why": [
        "vendor"
      ]
    }
  },
  "kind": "anchor.page",
  "links": {
    "api": "https://www.anchorterminal.com/api/v1/index.json",
    "html": "https://www.anchorterminal.com/tools/cnvs-whiteboard",
    "json": "https://www.anchorterminal.com/tools/cnvs-whiteboard.json",
    "llms": "https://www.anchorterminal.com/llms.txt",
    "markdown": "https://www.anchorterminal.com/tools/cnvs-whiteboard.md",
    "slim": "https://www.anchorterminal.com/tools/cnvs-whiteboard.min.md"
  },
  "markdown": "# cnvs.app\n\n\u003e Indexed, not reviewed: facts from the official MCP registry and our own checks. No score, grade or rank, and not in the rankings until the panel reviews it. How the index works: https://www.anchorterminal.com/indexed/\n\n- Kind: MCP server, by cnvs.app (https://cnvs.app)\n- Listed because: It's published in the registry under cnvs.app, a namespace the registry only gives to whoever proves they control that domain.\n- What the official MCP registry says: Real-time collaborative whiteboard — AI agents and humans edit the same board live over MCP.\n\n## Facts\n\n- MCP registry: `app.cnvs/whiteboard` 1.0.2\n- Endpoint: https://cnvs.app/mcp (streamable HTTP)\n- Source: https://github.com/lksrz/cnvs-whiteboard-skills\n- Website: https://cnvs.app\n- GitHub stars: 1\n- Registry entry updated: 2026-06-15\n\n## Tools\n\n- Tools it lists (25, about 8,632 tokens of context, `tools/list` without credentials, checked 2026-10-04 22:21 UTC):\n  - `open_board` (writes): ALWAYS call this first when given a board URL or ID. Resolves the canonical board id and auto-creates the board row if it does not exist yet. Returns a summary…\n  - `create_board` (writes): Create a fresh board in ONE call — optionally pre-filled with content, auto-laid-out, and/or PIN-locked at create time. Mirrors the extended `POST /api/boards`…\n  - `get_board` (writes): Full structured JSON state of a board: texts (id, x, y, content, color, width, postit, author), strokes (id, points, color, author), images (id, x, y, width,…\n  - `get_preview` (read-only): Compact schematic SVG render of the board (typically a few kB even for dense boards). Returns both an image/svg+xml content block (you can SEE it) and the raw…\n  - `add_text` (writes): Create a NEW text node, or update an existing one (pass the same `id` to overwrite content/position in place — preferred over creating a duplicate). Supports…\n  - `add_link` (writes): Drop a URL capsule onto the board — rendered as a clickable pill showing the hostname. Use this instead of `add_text` when the node is just a link; the capsule…\n  - `add_image` (writes): Place a raster or SVG image on the board at (x, y) with explicit width/height in board pixels. `data_url` MUST be a…\n  - `draw_stroke` (writes): Draw a freehand stroke on the board. Use for arrows, underlines, connector lines, annotations, or simple shapes — a straight line needs two points, a rough…\n  - `move` (writes): Reposition an existing item to a new (x, y) without retyping its content. Works for every item kind: `text` and `link` set the top-left to (x, y); `line`…\n  - `erase` (writes): Delete a single item by id. `kind` MUST match the item type: 'text' for text nodes, 'line' for freehand strokes, 'image' for images — the wrong kind silently…\n  - `wait_for_update` (read-only): Long-poll: blocks until the next edit lands on this board, then returns. WHEN TO CALL THIS: if your MCP client does NOT surface…\n  - `set_board_mode` (writes): Choose whether this board is a freeform whiteboard ('draw', the default) or a kanban task board ('todo'). Mode is switchable WHENEVER the board is empty of…\n  - `create_column` (writes): Add a kanban column (swimlane) to a 'todo' board. Generates and returns a stable column id. `sort` is a float ordering key (ascending); omit to default to 0.…\n  - `update_column` (writes): Rename, reorder, recolor or move an existing kanban column. Requires the column `id` (from `list_tasks`). Pass `title`, `sort`, `lane` and/or `color` to change…\n  - `delete_column` (writes): Delete a kanban column by id. Tasks in the column are removed with it. Get the id from `list_tasks`.\n  - `create_task` (writes): Create a task (card) in a column on a 'todo' board. Generates and returns a stable task id. `column_id` must reference an existing column (see `list_tasks`).…\n  - `update_task` (writes): Update an existing task by `id` (from `list_tasks`). Pass only the fields you want to change: `name`, `description`, `due_date`, `priority` ('H'|'M'|'L'),…\n  - `move_task` (writes): Move a task to a column at a given sort position — the kanban drag-and-drop primitive. `column_id` is the destination column and `sort` its float order key…\n  - `delete_task` (writes): Delete a task (card) by id. Get the id from `list_tasks`.\n  - `list_tasks` (read-only): Read the full kanban state of a 'todo' board: `{ mode, columns, tasks }`, both ordered by their `sort` key (ascending). Each task carries its hot fields (name,…\n  - `set_lane` (writes): Set (or clear) the title of a kanban row (lane). Lanes group columns into horizontal swimlanes; a lane is identified by its integer `lane` index (the same…\n  - `set_column_width` (writes): Set the shared kanban column width in pixels for a 'todo' board (all columns share one width). Clamped to [200, 480]. Read the current value as `colWidth` from…\n  - `create_tasks` (writes): Bulk-create multiple task cards in one call — far cheaper than calling `create_task` N times. Pass `tasks`: an array of task objects, each with `column_id`…\n  - `query_tasks` (read-only): Read tasks from a 'todo' board with server-side filtering — handy for 'what's overdue?' / 'what's assigned to X?' without pulling the whole board. All filters…\n  - `export_tasks` (read-only): Export a 'todo' board's columns + tasks as a single text document. `format` is 'markdown' (a checklist grouped by column, the default) or 'csv' (one row per…\n- How its tools read to an agent (0 errors, 26 warnings, 1 note, about 8,632 tokens; rules at https://www.anchorterminal.com/check.md; not part of the score):\n  - warn TC11 add_image: 9 parameters without a description: author, board_id, data_url, height, id, thumb_data_url and 3 more\n  - warn TC11 add_link: 5 parameters without a description: author, board_id, url, x, y\n  - warn TC11 add_text: 5 parameters without a description: board_id, content, postit, x, y\n  - warn TC11 create_column: 2 parameters without a description: board_id, title\n  - warn TC11 create_task: 5 parameters without a description: assignee, board_id, column_id, description, name\n  - warn TC11 create_tasks: 1 parameter without a description: board_id\n  - warn TC11 delete_column: 2 parameters without a description: board_id, id\n  - warn TC11 delete_task: 2 parameters without a description: board_id, id\n  - warn TC11 draw_stroke: 4 parameters without a description: author, board_id, color, id\n  - warn TC11 erase: 3 parameters without a description: board_id, id, kind\n  - warn TC11 export_tasks: 1 parameter without a description: board_id\n  - warn TC11 get_board: 1 parameter without a description: board_id\n  - warn TC11 get_preview: 1 parameter without a description: board_id\n  - warn TC11 list_tasks: 1 parameter without a description: board_id\n  - warn TC11 move: 4 parameters without a description: board_id, id, x, y\n  - warn TC11 move_task: 4 parameters without a description: board_id, column_id, id, sort\n  - warn TC11 query_tasks: 3 parameters without a description: board_id, done, priority\n  - warn TC11 set_board_mode: 1 parameter without a description: board_id\n  - warn TC11 set_column_width: 1 parameter without a description: board_id\n  - warn TC11 set_lane: 1 parameter without a description: board_id\n  - warn TC11 update_column: 3 parameters without a description: board_id, id, title\n  - warn TC11 update_task: 8 parameters without a description: assignee, board_id, column_id, description, id, name and 2 more\n  - warn TC11 wait_for_update: 2 parameters without a description: board_id, timeout_ms\n  - warn TC12 draw_stroke: no type for points\n\n- JSON: https://www.anchorterminal.com/api/v1/tools/cnvs-whiteboard.json\n- Being indexed says nothing about quality, and nobody can pay for it. Ask for a review: https://www.anchorterminal.com/builders/#claiming\n",
  "meta": {
    "attribution": "Anchor Terminal (https://www.anchorterminal.com)",
    "docs": "https://www.anchorterminal.com/docs/",
    "generatedAt": "2026-10-05",
    "license": "CC-BY-4.0",
    "method": "https://www.anchorterminal.com/benchmark/",
    "methodology": "0.3",
    "openapi": "https://www.anchorterminal.com/openapi.json",
    "preview": false,
    "run": "2026-10-01",
    "runLabel": "October 2026 research run"
  },
  "page": {
    "breadcrumbs": [
      {
        "name": "Home",
        "url": "https://www.anchorterminal.com/"
      },
      {
        "name": "Terminal",
        "url": "https://www.anchorterminal.com/tools/"
      },
      {
        "name": "Indexed",
        "url": "https://www.anchorterminal.com/indexed/"
      },
      {
        "name": "cnvs.app",
        "url": ""
      }
    ],
    "description": "cnvs.app, an MCP server by cnvs.app, listed from the official MCP registry. Indexed, not reviewed: facts and our own checks, no score or ranking. Real-time collaborative whiteboard — AI agents and humans edit the same board live over MCP.",
    "facts": [
      "not reviewed",
      "not ranked",
      "facts only"
    ],
    "h1": "cnvs.app",
    "image": "https://www.anchorterminal.com/assets/og/indexed.png",
    "path": "/tools/cnvs-whiteboard",
    "published": "",
    "section": "indexed",
    "title": "cnvs.app: MCP server, indexed from the official MCP registry",
    "toc": null,
    "updated": "2026-10-05",
    "url": "https://www.anchorterminal.com/tools/cnvs-whiteboard"
  },
  "tokens": {
    "markdown": 2150,
    "slim": 2080
  },
  "version": 1
}
