{"ok":true,"site":{"host":"agentdraw.app","url":"https://agentdraw.app/","type":"live","desc":"Excalidraw with WebMCP: a local-first whiteboard that an AI agent in ChatGPT or Codex can read and draw on. No install, no server.","tools":[{"name":"get_capabilities","kind":"answer","impl":"imperative","description":"What you can draw on this Excalidraw whiteboard: element types, style options, defaults, limits, arrow binding rules, and layout guidance. Read once per session before inspecting.","title":"Read whiteboard capabilities","annotations":{"readOnlyHint":true,"idempotentHint":true},"inputSchema":{"type":"object","properties":{},"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"inspect_canvas","kind":"answer","impl":"imperative","description":"Read every element on the whiteboard in a compact form: type, bounding box, text or label, bindings, absolute points for strokes and lines (sampled to 64), and for the person’s strokes the nearIds of shapes they touch. Also returns the viewport (scene coordinates), what the person has selected, the scene bounds, a suggested empty origin for new content, and how many elements the person changed since you last looked. The only type you can read but not create is freedraw. Embeddables carrying html report html: { chars, excerpt } instead of a link; pass includeHtml: true together with ids to get html.text, the full source. Pass sinceRevision to get only the elements that changed since then, plus the change log. detail: \"outline\" drops styles and points and keeps geometry, text, and bindings; detail: \"graph\" returns the board as a graph (elements are the nodes, plus graph.edges with from/to/text, graph.frames with their children, and graph.marks for the person’s strokes), the cheapest way to understand a flow or architecture diagram; every element carries by: \"agent\" or \"person\"; limit (default 250, max 500) and cursor page through large boards, and nextCursor tells you when there is more; a cursor is bound to the revision it was issued at and answers cursor_expired if the board changed in between, so start over from the first page. A label is a separate text element bound to its shape, so a labelled shape counts as two elements everywhere: elementCount counts the whole board, matchedCount what matched after filters, returnedCount what this page holds. Writes need the epoch and revision from this call or from your last apply_patch response.","title":"Inspect the whiteboard","annotations":{"readOnlyHint":true,"idempotentHint":true,"untrustedContentHint":true},"inputSchema":{"type":"object","properties":{"sinceRevision":{"type":"integer","minimum":0},"ids":{"type":"array","minItems":1,"maxItems":200,"uniqueItems":true,"items":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,119}$"}},"frameId":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,119}$"},"viewportOnly":{"type":"boolean"},"detail":{"type":"string","enum":["full","outline","graph"]},"includeHtml":{"type":"boolean"},"limit":{"type":"integer","minimum":1,"maximum":500},"cursor":{"type":"string","pattern":"^c[0-9]{1,7}\\.[0-9]{1,9}$"}},"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"apply_patch","kind":"act","impl":"imperative","description":"Atomically create, update, delete, move, duplicate, or restyle up to 50 elements per call: rectangles, ellipses, diamonds, text, arrows and lines, frames, embeddable web pages, and images from a base64 dataUrl. An embeddable takes either link (a web page) or html (your own page, rendered live in a sandboxed frame; update it with html again). Place a new element without coordinates with at: { relativeTo, side, gap?, align? } and it lands beside that element, joining its frame. move shifts ids by dx/dy with their labels and frame children; duplicate copies ids (labels, children, and the arrows between them included) offset by dx/dy and reports each copy with its sourceId; style restyles ids in one go. Labels are measured automatically; update a shape or arrow with label: { text } to rename it (label: null removes it), and resizing re-centres the label. Text and labels take fontSize, fontFamily (hand, normal, code, display), textAlign, and verticalAlign, on create and on update. Arrows with start/end { id } are anchored to those shapes’ edges and re-routed, labels included, when you move or resize the shapes. Moving a frame moves its children and labels. Operations may reference elements created anywhere in the same patch (an arrow before its shapes, a child before its frame); they are applied in dependency order. Requires the epoch and revision from your latest inspect_canvas or apply_patch; a stale revision is rejected whole with revision_conflict, and every invalid operation is listed in error.details.errors. Returns a patchId for revert_patch, created ids with bounds and boundTextId, the ids you updated, the ids touched as side effects, and the ids removed.","title":"Draw on the whiteboard","annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false},"inputSchema":{"type":"object","properties":{"epoch":{"type":"string","minLength":1,"maxLength":120},"baseRevision":{"type":"integer","minimum":0},"operations":{"type":"array","minItems":1,"maxItems":50,"items":{"oneOf":[{"type":"object","properties":{"op":{"const":"create"},"id":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,119}$"},"type":{"enum":["rectangle","ellipse","diamond","text","arrow","line","frame","embeddable","image"]},"x":{"type":"number","minimum":-1000000,"maximum":1000000},"y":{"type":"number","minimum":-1000000,"maximum":1000000},"width":{"type":"number","minimum":1,"maximum":20000},"height":{"type":"number","minimum":1,"maximum":20000},"angle":{"type":"number"},"frameId":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,119}$"},"locked":{"type":"boolean"},"link":{"type":"string","maxLength":2048},"customData":{"type":"object"},"strokeColor":{"type":"string","pattern":"^(transparent|#([0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8}))$"},"backgroundColor":{"type":"string","pattern":"^(transparent|#([0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8}))$"},"fillStyle":{"enum":["hachure","cross-hatch","solid","zigzag"]},"strokeWidth":{"type":"number","minimum":0.5,"maximum":8},"strokeStyle":{"enum":["solid","dashed","dotted"]},"roughness":{"type":"number","minimum":0,"maximum":2},"opacity":{"type":"number","minimum":0,"maximum":100},"roundness":{"enum":["round","sharp"]},"text":{"type":"string","maxLength":4000},"fontSize":{"type":"number","minimum":8,"maximum":200},"fontFamily":{"enum":["hand","normal","code","display"]},"textAlign":{"enum":["left","center","right"]},"verticalAlign":{"enum":["top","middle","bottom"]},"label":{"type":"object","properties":{"text":{"type":"string","maxLength":4000},"fontSize":{"type":"number","minimum":8,"maximum":200},"fontFamily":{"enum":["hand","normal","code","display"]},"textAlign":{"enum":["left","center","right"]},"verticalAlign":{"enum":["top","middle","bottom"]}},"required":["text"],"additionalProperties":false},"name":{"type":"string","maxLength":200},"points":{"type":"array","minItems":2,"maxItems":500,"items":{"type":"array","items":{"type":"number"},"minItems":2,"maxItems":2}},"start":{"oneOf":[{"type":"object","properties":{"id":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,119}$"}},"required":["id"],"additionalProperties":false},{"type":"object","properties":{"x":{"type":"number","minimum":-1000000,"maximum":1000000},"y":{"type":"number","minimum":-1000000,"maximum":1000000}},"required":["x","y"],"additionalProperties":false}]},"end":{"oneOf":[{"type":"object","properties":{"id":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,119}$"}},"required":["id"],"additionalProperties":false},{"type":"object","properties":{"x":{"type":"number","minimum":-1000000,"maximum":1000000},"y":{"type":"number","minimum":-1000000,"maximum":1000000}},"required":["x","y"],"additionalProperties":false}]},"startArrowhead":{"enum":["arrow","bar","dot","triangle","none"]},"endArrowhead":{"enum":["arrow","bar","dot","triangle","none"]},"at":{"type":"object","properties":{"relativeTo":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,119}$"},"side":{"enum":["right","left","below","above"]},"gap":{"type":"number","minimum":0,"maximum":5000},"align":{"enum":["start","center","end"]}},"required":["relativeTo","side"],"additionalProperties":false},"dataUrl":{"type":"string","maxLength":1500000},"html":{"type":"string","maxLength":200000}},"required":["op","type"],"additionalProperties":false},{"type":"object","properties":{"op":{"const":"update"},"id":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,119}$"},"x":{"type":"number","minimum":-1000000,"maximum":1000000},"y":{"type":"number","minimum":-1000000,"maximum":1000000},"width":{"type":"number","minimum":1,"maximum":20000},"height":{"type":"number","minimum":1,"maximum":20000},"angle":{"type":"number"},"frameId":{"anyOf":[{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,119}$"},{"type":"null"}]},"label":{"anyOf":[{"type":"object","properties":{"text":{"type":"string","maxLength":4000},"fontSize":{"type":"number","minimum":8,"maximum":200},"fontFamily":{"enum":["hand","normal","code","display"]},"textAlign":{"enum":["left","center","right"]},"verticalAlign":{"enum":["top","middle","bottom"]}},"required":["text"],"additionalProperties":false},{"type":"null"}]},"locked":{"type":"boolean"},"link":{"anyOf":[{"type":"string","maxLength":2048},{"type":"null"}]},"customData":{"anyOf":[{"type":"object"},{"type":"null"}]},"strokeColor":{"type":"string","pattern":"^(transparent|#([0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8}))$"},"backgroundColor":{"type":"string","pattern":"^(transparent|#([0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8}))$"},"fillStyle":{"enum":["hachure","cross-hatch","solid","zigzag"]},"strokeWidth":{"type":"number","minimum":0.5,"maximum":8},"strokeStyle":{"enum":["solid","dashed","dotted"]},"roughness":{"type":"number","minimum":0,"maximum":2},"opacity":{"type":"number","minimum":0,"maximum":100},"roundness":{"enum":["round","sharp"]},"text":{"type":"string","maxLength":4000},"fontSize":{"type":"number","minimum":8,"maximum":200},"fontFamily":{"enum":["hand","normal","code","display"]},"textAlign":{"enum":["left","center","right"]},"verticalAlign":{"enum":["top","middle","bottom"]},"name":{"type":"string","maxLength":200},"html":{"type":"string","maxLength":200000}},"required":["op","id"],"additionalProperties":false},{"type":"object","properties":{"op":{"const":"delete"},"id":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,119}$"}},"required":["op","id"],"additionalProperties":false},{"type":"object","properties":{"op":{"const":"move"},"ids":{"type":"array","minItems":1,"maxItems":50,"uniqueItems":true,"items":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,119}$"}},"dx":{"type":"number","minimum":-1000000,"maximum":1000000},"dy":{"type":"number","minimum":-1000000,"maximum":1000000}},"required":["op","ids"],"additionalProperties":false},{"type":"object","properties":{"op":{"const":"duplicate"},"ids":{"type":"array","minItems":1,"maxItems":50,"uniqueItems":true,"items":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,119}$"}},"dx":{"type":"number","minimum":-1000000,"maximum":1000000},"dy":{"type":"number","minimum":-1000000,"maximum":1000000}},"required":["op","ids"],"additionalProperties":false},{"type":"object","properties":{"op":{"const":"style"},"ids":{"type":"array","minItems":1,"maxItems":50,"uniqueItems":true,"items":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,119}$"}},"strokeColor":{"type":"string","pattern":"^(transparent|#([0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8}))$"},"backgroundColor":{"type":"string","pattern":"^(transparent|#([0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8}))$"},"fillStyle":{"enum":["hachure","cross-hatch","solid","zigzag"]},"strokeWidth":{"type":"number","minimum":0.5,"maximum":8},"strokeStyle":{"enum":["solid","dashed","dotted"]},"roughness":{"type":"number","minimum":0,"maximum":2},"opacity":{"type":"number","minimum":0,"maximum":100},"roundness":{"enum":["round","sharp"]}},"required":["op","ids"],"additionalProperties":false}]}}},"required":["epoch","baseRevision","operations"],"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"revert_patch","kind":"act","impl":"imperative","description":"Roll back one patch you applied earlier, identified by the patchId that apply_patch returned, without touching anything else on the board. Refused with revert_conflict if the person or a later patch changed any of the affected elements since; then inspect and fix by hand. Needs the current epoch and revision like apply_patch. Only the last 20 patches of this page load can be reverted. The person can still undo everything with Cmd+Z.","title":"Undo one of your patches","annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false},"inputSchema":{"type":"object","properties":{"epoch":{"type":"string","minLength":1,"maxLength":120},"baseRevision":{"type":"integer","minimum":0},"patchId":{"type":"string","minLength":1,"maxLength":120}},"required":["epoch","baseRevision","patchId"],"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"import_scene","kind":"act","impl":"imperative","description":"Load an .excalidraw document (the text from export_canvas, a file from the person’s repository, or a template) as JSON text or object. mode \"append\" (default) places it beside the existing content, or at the given at: { x, y }; mode \"replace\" clears the board first. Ids are regenerated, so inspect_canvas afterwards to learn them. Needs the current epoch and revision like apply_patch and returns a patchId for revert_patch. At most 2000 elements.","title":"Load a saved diagram onto the board","annotations":{"readOnlyHint":false,"destructiveHint":true,"idempotentHint":false},"inputSchema":{"type":"object","properties":{"epoch":{"type":"string","minLength":1,"maxLength":120},"baseRevision":{"type":"integer","minimum":0},"scene":{"anyOf":[{"type":"string","maxLength":2000000},{"type":"object"}]},"mode":{"type":"string","enum":["append","replace"]},"at":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"}},"required":["x","y"],"additionalProperties":false}},"required":["epoch","baseRevision","scene"],"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"focus_elements","kind":"act","impl":"imperative","description":"Select one or more elements and scroll the person’s view to them. Does not change the document, but it does change selectionIds.","title":"Show elements to the person","annotations":{"readOnlyHint":false,"destructiveHint":false,"idempotentHint":true},"inputSchema":{"type":"object","properties":{"ids":{"type":"array","minItems":1,"maxItems":50,"uniqueItems":true,"items":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,119}$"}}},"required":["ids"],"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"capture_canvas","kind":"act","impl":"imperative","description":"Render the whole whiteboard, the given element ids (their labels come along), or one frame by frameId, to a PNG data URL with the longest side at most 1600px, so you can look at what was drawn, including the person’s freehand sketches. The response’s scale is pixels per scene unit; on a large or scattered board the whole-board capture is too small to read, so pass the ids of the part you care about instead.","title":"See the whiteboard as an image","annotations":{"readOnlyHint":true,"idempotentHint":true,"untrustedContentHint":true},"inputSchema":{"type":"object","properties":{"ids":{"type":"array","minItems":1,"maxItems":200,"uniqueItems":true,"items":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,119}$"}},"frameId":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,119}$"}},"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"},{"name":"export_canvas","kind":"act","impl":"imperative","description":"Return the whole board, the given element ids (their labels come along), or one frame by frameId, as text you can save: format \"svg\" for a picture, or \"excalidraw\" for the standard .excalidraw JSON that opens on excalidraw.com and in this app. Use it to put a diagram into a repository, a README, or a document. SVG fonts are not inlined unless inlineFonts is true, so the file stays small and any viewer can open it. The response carries the text, its character count, a suggested file name, and the bounds. Exports over 2,000,000 characters are refused; pass ids for the part you need.","title":"Export the whiteboard as a file","annotations":{"readOnlyHint":true,"idempotentHint":true,"untrustedContentHint":true},"inputSchema":{"type":"object","properties":{"format":{"type":"string","enum":["svg","excalidraw"]},"ids":{"type":"array","minItems":1,"maxItems":500,"uniqueItems":true,"items":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,119}$"}},"frameId":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,119}$"},"inlineFonts":{"type":"boolean"}},"required":["format"],"additionalProperties":false},"hasHandler":true,"hasExecute":true,"__source":"spec","executable":true,"handlerField":"execute"}],"category":"Productivity & Business","favicon":"/favicons/agentdraw.app.png","apiSurface":"spec","toolCount":8}}