8.1 KiB
VectorCraft MCP server
vectorcraft-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 VectorCraft documents.
It has two backends:
| Mode | How | What works |
|---|---|---|
| Remote | vectorcraft-cli mcp --connect 127.0.0.1:7979 (the app must run with vectorcraft --control 7979) |
Everything. Tool calls are forwarded over the control protocol, so you watch the app change live. |
| Headless | vectorcraft-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 vectorcraft-cli
claude mcp add vectorcraft -- "$PWD/target/release/vectorcraft-cli" mcp
# or pin a mode:
claude mcp add vectorcraft-headless -- "$PWD/target/release/vectorcraft-cli" mcp --headless
claude mcp add vectorcraft-app -- "$PWD/target/release/vectorcraft-cli" mcp --connect 127.0.0.1:7979
Other clients use the same command in their JSON config:
{"mcpServers": {"vectorcraft": {"command": "/abs/path/target/release/vectorcraft-cli", "args": ["mcp"]}}}
For a live session, start the app first: cargo run --release -p vectorcraft -- --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 .vectorcraft or .svg as a new active document. |
save_file |
{path?} |
Saves in the native .vectorcraft format. |
export |
{path, format?, scale?, selection?} |
svg, pdf, png, jpg, webp or vectorcraft. When format is omitted, it comes from the path's extension. selection: true exports the selected objects cropped to their bounds; outlineText: true writes SVG text as paths. Live effects are kept. |
add_text |
{text, x?, y?, width?, height?, path?, mode?, pathEffect?, size?, font?, color?} |
Point type at (x, y); area type with width/height; or path + mode (area/onPath) to flow text in or along a path, with pathEffect (rainbow, skew, 3dRibbon, stairStep, gravity). |
apply_effect |
{effect?, params?, ids?} |
Appends a live effect. Without effect, returns the effect catalogue with parameters and defaults. |
pathfinder |
{operation, ids?} |
unite, minusFront, intersect, exclude, divide, trim, merge, crop, outline, minusBack. For a live version, apply the pathfinder.* effect to a group. |
transform |
{ids?, dx?, dy?, rotate?, scale?, scaleX?, scaleY?, reflect?, shear?, origin?, copy?} |
Runs move, rotate, scale, reflect, shear in that order. With copy, the first step duplicates. |
create_graph |
{type?, x, y, width, height, csv? | series?, categories?, rows?} |
The nine Illustrator graph types. Edit later with graph.setData / graph.setType via run_command. |
text_wrap |
{ids?, offset?, invert?, release?} |
Area type below the objects (same layer) flows around them. |
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 |
|---|---|
vectorcraft://document |
document.inspect summary (JSON) |
vectorcraft://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/vectorcraft-cli mcp --headless
Headless batch CLI
vectorcraft-cli commands # command catalogue (JSON)
vectorcraft-cli run --in in.svg \
--cmd select.all --cmd paint.setFill --params '{"color":"#ff0000"}' \
--export out.svg --export out.png --scale 2
vectorcraft-cli run --cmd file.new --params '{"width":800,"height":600}' \
--cmd shape.star --params '{"cx":400,"cy":300,"radius1":200,"radius2":90}' \
--export star.vectorcraft
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.