Metadata-Version: 2.4
Name: eazydraw
Version: 1.2.0
Summary: Python client and MCP server for the EazyDraw Automation API
Author-email: Dave Mattson <davemattson@eazydraw.com>
Maintainer-email: "Dekorra Optics, LLC" <davemattson@eazydraw.com>
License-Expression: MIT
Project-URL: Homepage, https://www.eazydraw.com
Project-URL: Documentation, https://www.eazydraw.com/ezdHelpPages/apiReference.htm
Keywords: eazydraw,automation,api,rest,mcp,model context protocol,claude,drawing,vector,graphics
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Operating System :: MacOS
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Topic :: Multimedia :: Graphics
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.31
Requires-Dist: pydantic>=2.6
Provides-Extra: mcp
Requires-Dist: mcp<2,>=1.2; extra == "mcp"
Provides-Extra: dev
Requires-Dist: pyyaml>=6.0; extra == "dev"
Requires-Dist: openapi-spec-validator>=0.7; extra == "dev"
Dynamic: license-file

# eazydraw — Python client and MCP server for EazyDraw

[EazyDraw](https://www.eazydraw.com) 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 the `client_name` field", "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](https://www.eazydraw.com/ezdHelpPages/apiReference.htm) Help page.

## Install

```bash
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:

```python
from eazydraw import EazyDraw, DEFAULT_SOCKET
ed = EazyDraw(token="...")                                # direct build, TCP
ed = EazyDraw(token="...", socket_path=DEFAULT_SOCKET)    # App Store build
```

## Python quickstart

```python
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:

```python
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:

```python
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](https://docs.astral.sh/uv/)'s `uvx`, so
there is nothing to install by hand, and `--refresh-package` picks up new
releases automatically:

```json
{
  "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:

- `render` returns a PNG inline so the agent can see the result (96 dpi by
  default). `export_drawing` writes a file instead (PDF, SVG, or 144 dpi PNG/JPEG
  by default) to `~/EazyDraw-Renders` (or `EAZYDRAW_RENDER_DIR`, read at launch)
  and returns only the path. `save_render` is the same tool under its earlier name.
- An "active drawing" is tracked, so with one drawing open the tools do not
  need a `drawing` argument.
- Environment: `EAZYDRAW_TOKEN` (required), `EAZYDRAW_SOCKET`, `EAZYDRAW_HOST`,
  `EAZYDRAW_PORT`, `EAZYDRAW_RENDER_DIR`.
- Run the server by hand with `eazydraw-mcp` or `python -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
