eazydraw — Python client and MCP server for EazyDraw
EazyDraw is a vector drawing application for the Mac: technical drawings, diagrams, illustrations, schematics, and layouts, with layers, libraries, and a full set of line, fill, and text styling. EazyDraw 12 includes an Automation API, an HTTP interface served by the running app.
This package is the Python side of that API. It gives you two ways to drive EazyDraw:
eazydraw— a Python client. One class,EazyDraw, with a method for every API endpoint. Open, create, and save drawings; add and style graphics; edit text; manage layers; export to PDF, SVG, PNG, or JPEG.eazydraw-mcp— a Model Context Protocol server. Exposes the same capabilities to an AI agent such as Claude as intent-level tools that work by name ("fill theclient_namefield", "put the legend beside the chart", "render it"). The agent never sees UUIDs or your API token.
Requires macOS, Python 3.10+, and EazyDraw 12 with the Automation API turned on in EazyDraw ▸ Settings ▸ API Settings.
What you can do
Drawings — list open drawings, open a file, create a blank drawing, Save and Save As, close, undo and redo (every API call is one undo step), read and set the selection, page setup, grids, drawing scale, and the window viewport.
Layers — list, create, rename, reorder, and delete layers, show/hide/lock them, select by layer, and apply saved layer configurations.
Graphics — add shapes (rectangles, ovals, lines, polygons, and more), paths from node lists, and curves fitted through points. Name, move, resize, scale, rotate, flip, duplicate, group and ungroup, combine (union, difference, intersection), reorder front-to-back, move between layers, lock, and delete.
Styling — stroke and fill color, line width, dash patterns, shadows, gradients, fill patterns, hatching, arrowheads, calligraphic brush profiles, conduits (double-line paths) with crossover styles, and path offsets.
Text — read and set text, with fit information so you know whether it overflowed; work at the run level for mixed fonts and colors; insert, align, highlight, shadow, and disconnect linked text boxes; edit annotations.
Images — insert an image or PDF, or fit one into a named slot.
Libraries — browse the installed libraries and place their elements into a drawing.
Arrange (semantic layer and MCP) — place a graphic beside a reference, nudge, anchor to page positions (center, corners, edges), align, and distribute.
Render and export — render to PNG at a chosen dpi, or export a drawing,
layer, or graphic as PDF, SVG, PNG, JPEG, or the native .ezdjson format.
The MCP server exposes about 90 tools covering the list above, plus
eazydraw://drawings and eazydraw://drawing/{uuid}/fields resources. The
authoritative reference for both the API and the tools is the
API Reference Help page.
Install
pip install eazydraw # the Python client
pip install "eazydraw[mcp]" # client + MCP server (adds the eazydraw-mcp command)
Generate a bearer token in EazyDraw's API Settings (Reveal / Copy). Keep EazyDraw running with the API enabled; the package talks to the live app.
Transport: TCP or UNIX socket
The direct-download EazyDraw serves the API on localhost:52737. The App Store
EazyDraw is sandboxed and serves the same API on a UNIX-domain socket in its
container instead. API Settings shows which one your copy uses. Everything else
is identical:
from eazydraw import EazyDraw, DEFAULT_SOCKET
ed = EazyDraw(token="...") # direct build, TCP
ed = EazyDraw(token="...", socket_path=DEFAULT_SOCKET) # App Store build
Python quickstart
from eazydraw import EazyDraw
ed = EazyDraw(token="7b3f...") # from API Settings -> Reveal
ed.status()
# {'status': 'OK', 'version': '12.10.0', 'build': '52075'}
# Open a drawing and walk to the graphics on its first layer
d = ed.open_drawing("~/Documents/sketch.ezdjson")
layers = ed.layers(d["uuid"])
graphics = ed.layer_graphics(d["uuid"], layers[0]["uuid"])
# Export it as a PNG
ed.export_drawing(d["uuid"], "png", save_to="~/Desktop/sketch.png")
ed.close_drawing(d["uuid"])
# Start from nothing
n = ed.new_drawing("Plan")
lyr = ed.layers(n["uuid"])[0]["uuid"]
box = ed.add_shape(n["uuid"], lyr, shape="rectangle",
bounds={"x": 72, "y": 72, "width": 200, "height": 100}, name="frame")
ed.set_style(n["uuid"], lyr, box["graphicUUID"],
fill={"color": "#DDEEFF"}, stroke={"width": 2})
ed.set_selection(n["uuid"], [box["graphicUUID"]])
ed.save_drawing(n["uuid"], path="~/Documents/plan.ezdjson")
Methods take UUIDs as positional strings in path order and return the raw JSON
as dicts and lists. Collection endpoints return the list directly. Non-2xx
responses raise EazyDrawError(status_code, message, body), and the last
requests response is kept on ed.last_response when the status code matters
(201 newly opened vs 200 already open, for example).
Typed models (optional)
eazydraw.models has pydantic v2 models mirroring the API's JSON shapes:
from eazydraw import Graphic
g = Graphic.model_validate(ed.graphic(D, L, G))
g.hidden_bounds.width, g.is_group # snake_case fields
g.model_dump(by_alias=True) # back to wire form
Working by name
eazydraw.semantic.Semantic resolves names to graphics and does layout
geometry client-side, so scripts can say what they mean:
from eazydraw.semantic import Semantic
sem = Semantic(ed)
sem.move_beside(d["uuid"], target="legend", reference="chart", direction="right", gap=24)
sem.align(d["uuid"], ["a", "b", "c"], edge="left")
MCP server with Claude Desktop
Add this to ~/Library/Application Support/Claude/claude_desktop_config.json
and restart Claude Desktop. It uses uv's uvx, so
there is nothing to install by hand, and --refresh-package picks up new
releases automatically:
{
"mcpServers": {
"eazydraw": {
"command": "uvx",
"args": ["--refresh-package", "eazydraw", "--from", "eazydraw[mcp]", "eazydraw-mcp"],
"env": { "EAZYDRAW_TOKEN": "PASTE_TOKEN_HERE" }
}
}
}
For the App Store EazyDraw add "EAZYDRAW_SOCKET": "default" to env. The
Copy Claude Desktop config button in API Settings produces this block with
the right token and transport filled in.
Then ask Claude something like: "Open ~/Documents/engagement.ezdjson, list its
fields, set client_name to 'Ryan Mattson', then render it so I can see."
Notes:
renderreturns a PNG inline so the agent can see the result (96 dpi by default).export_drawingwrites a file instead (PDF, SVG, or 144 dpi PNG/JPEG by default) to~/EazyDraw-Renders(orEAZYDRAW_RENDER_DIR, read at launch) and returns only the path.save_renderis the same tool under its earlier name.- An "active drawing" is tracked, so with one drawing open the tools do not
need a
drawingargument. - Environment:
EAZYDRAW_TOKEN(required),EAZYDRAW_SOCKET,EAZYDRAW_HOST,EAZYDRAW_PORT,EAZYDRAW_RENDER_DIR. - Run the server by hand with
eazydraw-mcporpython -m eazydraw.mcp.
Links
- EazyDraw: https://www.eazydraw.com
- API Reference (endpoints and MCP tools): https://www.eazydraw.com/ezdHelpPages/apiReference.htm
- Changelog: see CHANGELOG.md in the source distribution
- License: MIT
Release files for eazydraw 1.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| eazydraw-1.2.0.tar.gz | 66.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| eazydraw-1.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 129.8 kB
Release files / eazydraw-1.2.0.tar.gz
| Download URL | eazydraw-1.2.0.tar.gz |
|---|---|
| Size | 66.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7d33fbd55d2adda2e8895a6cd41e5d961a1af8c4ed91cd14584c882cf971b9c9
|
|
BLAKE2b-256 checksum How to use checksums |
de3ee0c6a048e103388d73fa4b9a66b0b8842403076e7bd4481ac5da166c02e3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.14
|
Release files / eazydraw-1.2.0-py3-none-any.whl
| Download URL | eazydraw-1.2.0-py3-none-any.whl |
|---|---|
| Size | 63.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
75bfe3c8c6c8669562d437e6cc11f7f72ea925b1feb0875af5c602d592808e35
|
|
BLAKE2b-256 checksum How to use checksums |
786fe8d411634de6138442c4ad0d00b0fa8f3c1bc1d3c8fbe94a162cc8a1e4fe
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.14
|