6.7 KiB
DrawCraft MCP server
drawcraft-cli mcp runs a Model Context Protocol server on stdio
(newline-delimited JSON-RPC 2.0, protocol 2025-06-18; 2025-03-26 and 2024-11-05 also accepted). Agents use it to
draw, inspect and look at DrawCraft documents.
It has two backends:
| Mode | How | What works |
|---|---|---|
| Remote | drawcraft-cli mcp --connect 127.0.0.1:7979 (the app must run with drawcraft --control 7979) |
Everything. Tool calls are forwarded over the control protocol, so you watch the app change live. |
| Headless | drawcraft-cli mcp --headless |
An in-process engine session with a CPU renderer. Everything except the UI-only tools (inspect_ui, type_text, open_panel, screenshot {window:true}). |
With no flag, the server tries 127.0.0.1:7979 and falls back to headless. Logs go to stderr; stdout carries
only protocol messages.
Build and register
cargo build --release -p drawcraft-cli
claude mcp add drawcraft -- "$PWD/target/release/drawcraft-cli" mcp
# or pin a mode:
claude mcp add drawcraft-headless -- "$PWD/target/release/drawcraft-cli" mcp --headless
claude mcp add drawcraft-app -- "$PWD/target/release/drawcraft-cli" mcp --connect 127.0.0.1:7979
Other clients use the same command in their JSON config:
{"mcpServers": {"drawcraft": {"command": "/abs/path/target/release/drawcraft-cli", "args": ["mcp"]}}}
For a live session, start the app first: cargo run --release -p drawcraft -- --control 7979.
Tools
Coordinates are points in document space: y points down, the origin is the first artboard's top-left, and a new
document is 612 × 792 (US Letter). New objects become the selection. Most commands act on the selection or on
explicit ids.
Paint values (fill, stroke) accept "#rrggbb", "none", [r,g,b] (0..1), {"c","m","y","k"}, {"gray"},
or a full paint.setFill params object ({"gradient": …}, {"swatch": "name"}).
| Tool | Arguments | Notes |
|---|---|---|
list_commands |
{filter?, enabledOnly?} |
The command catalogue: id, label, menu, shortcut, params doc, enablement. |
run_command |
{command, params?} |
Runs any command. Use it for everything without a dedicated tool. |
inspect_document |
{} |
Artboards, layer tree (ids, kinds, bounds, paint), selection, history, tool. |
inspect_ui |
{} |
UI state. Remote mode only. |
select_tool |
{tool} |
selection, directSelection, pen, rectangle, ellipse, polygon, star, lineSegment, … |
pointer_gesture |
{events:[{kind,x,y,mods?}], tool?, mods?} |
kind is one of down, drag, up, move, doubleclick. Events go through the same path as the mouse. |
draw_path |
{points | d, closed?, fill?, stroke?, strokeWidth?} |
points is [[x,y],…] or [{x,y,in?,out?,smooth?},…]. d is SVG path data. |
draw_shape |
{shape, …geometry, fill?, stroke?, strokeWidth?} |
rectangle/ellipse: x,y,width,height (plus radius for corners). polygon: cx,cy,radius,sides. star: cx,cy,radius1,radius2,points. line: x1,y1,x2,y2. |
set_paint |
{fill?, stroke?, strokeWidth?, ids?} |
Applies to the selection (or ids) and becomes the default for new art. |
press_key |
{key, mods?} |
Remote: a real key event. Headless: runs the command or tool bound to that shortcut, or sends the key to the busy tool. |
type_text |
{text} |
Remote only. |
invoke_menu |
{command, params?} |
Invokes a menu item by command id. Includes UI commands such as view.* and window.* in remote mode. |
open_panel |
{panel} |
Remote only. |
screenshot |
{path?, scale?, artboard?, window?} |
Returns MCP image content (image/png, base64) plus a text block. Renders the artboard; window:true captures the app window (remote only). |
open_file |
{path} |
Opens .drawcraft or .svg as a new active document. |
save_file |
{path?} |
Saves in the native .drawcraft format. |
export |
{path, format?, scale?} |
svg, png or drawcraft. When format is omitted, it comes from the path's extension. |
undo / redo |
{} |
Errors (unknown tool, bad arguments, a disabled or failing command) come back as a normal result with
isError: true and a message. The model can read the message and retry.
Resources
| URI | Content |
|---|---|
drawcraft://document |
document.inspect summary (JSON) |
drawcraft://document/json |
The complete document model (JSON) |
Examples
Draw, look, export:
{"name":"draw_shape","arguments":{"shape":"rectangle","x":72,"y":72,"width":200,"height":120,"radius":12,"fill":"#1e88e5","stroke":"none"}}
{"name":"draw_shape","arguments":{"shape":"star","cx":400,"cy":300,"radius1":90,"radius2":40,"points":5,"fill":"#ffc107","stroke":"#000000","strokeWidth":2}}
{"name":"draw_path","arguments":{"d":"M72 400 C 150 300 250 500 330 400","stroke":"#e53935","strokeWidth":4,"fill":"none"}}
{"name":"screenshot","arguments":{"scale":0.5}}
{"name":"export","arguments":{"path":"/tmp/art.svg"}}
Long-tail commands:
{"name":"list_commands","arguments":{"filter":"align"}}
{"name":"run_command","arguments":{"command":"select.all"}}
{"name":"run_command","arguments":{"command":"object.align","params":{"align":"left"}}}
{"name":"run_command","arguments":{"command":"object.group"}}
Drive a tool like a mouse:
{"name":"pointer_gesture","arguments":{"tool":"ellipse","events":[
{"kind":"down","x":100,"y":100},{"kind":"drag","x":150,"y":140},{"kind":"up","x":200,"y":180}]}}
Raw protocol (for debugging):
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"sh","version":"0"}}}' \
'{"jsonrpc":"2.0","method":"notifications/initialized"}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"draw_shape","arguments":{"shape":"ellipse","x":10,"y":10,"width":100,"height":80,"fill":"#ff0000"}}}' \
'{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"inspect_document","arguments":{}}}' \
| target/release/drawcraft-cli mcp --headless
Headless batch CLI
drawcraft-cli commands # command catalogue (JSON)
drawcraft-cli run --in in.svg \
--cmd select.all --cmd paint.setFill --params '{"color":"#ff0000"}' \
--export out.svg --export out.png --scale 2
drawcraft-cli run --cmd file.new --params '{"width":800,"height":600}' \
--cmd shape.star --params '{"cx":400,"cy":300,"radius1":200,"radius2":90}' \
--export star.drawcraft
run prints one JSON line per step (open, cmd, export) and exits non-zero on the first failure. --params
applies to the --cmd just before it. run also accepts the host commands file.open, file.save, file.export
and tool.select.