Metadata-Version: 2.5
Name: pac-vector
Version: 0.1.0
Summary: Local stdio MCP server for SVG editing via in-memory virtual documents, with a live browser preview
Requires-Python: >=3.11
Requires-Dist: lxml>=5.0
Requires-Dist: mcp[cli]<2.0.0,>=1.10.0
Requires-Dist: pillow>=10.0
Requires-Dist: resvg-py>=0.5.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == 'dev'
Description-Content-Type: text/markdown

# pac-vector

Local stdio MCP server: an SVG editor over in-memory **virtual documents** (one per
"window", like Inkscape), with a **live browser preview** of every edit.

- Content goes in as SVG markup; structure (layers, groups, masks, z-order) has typed tools.
- Layers are real Inkscape layers, so exported files open in Inkscape with layers intact.
- Every edit is atomic (a failed call changes nothing) and one undo step.
- `render` returns a PNG the agent can look at; rendering is resvg (no browser, no Cairo).

## Install

Same shape as pac-pincers: a pip package, run as a module by whatever Python it
was installed into.

```powershell
python -m pip install --upgrade pac-vector
claude mcp add pac-vector --scope user -- python -m pac_vector
```

As a plugin `.mcp.json` entry (mirrors the datatopia plugin's pac-pincers entry):

```json
"pac-vector": {
  "type": "stdio",
  "command": "${PAC_VECTOR_PYTHON:-python}",
  "args": ["-m", "pac_vector"],
  "env": {}
}
```

Development:

```powershell
python -m venv .venv
.\.venv\Scripts\python.exe -m pip install -e ".[dev]"
.\.venv\Scripts\python.exe run_tests.py -q
.\.venv\Scripts\python.exe -m build          # dist/pac_vector-<ver>.tar.gz + .whl
```

## Tools (17)

| Group | Tools |
|---|---|
| Documents | `doc_create` (blank or import), `doc_list`, `doc_set` (size, units, viewBox, background, fit), `doc_export` (svg/png, page/drawing/ids, plain), `doc_close` |
| Reading | `inspect` (outline or xml), `render` (PNG, optional crop to ids + bbox) |
| Editing | `add` (markup → layer/group, defs auto-routed), `update` (attrs/style/text/transform/label/hidden/locked on many ids), `replace` (one element or the whole drawing), `remove`, `arrange` (z-order, move between layers, duplicate, offset) |
| Structure | `group` (also new layers), `ungroup`, `mask` (mask or clip from id or markup), `unmask` |
| History | `undo` |

## Preview

`doc_create` / `doc_list` / `inspect` print `preview: http://127.0.0.1:<port>/#<doc>`.
The page has a tab per document, outlines the elements each edit touched, and
shows (and copies) the id of anything you click. The server lives inside the MCP
process: it starts on the first `doc_create` and dies with the session.

## Environment

| Variable | Default | Meaning |
|---|---|---|
| `PAC_VECTOR_PORT` | `0` (random) | Pin the preview port (falls back to random if busy) |
| `PAC_VECTOR_OPEN_BROWSER` | off | `1` opens the preview in the default browser on first start |
| `PAC_VECTOR_ROOT` | server cwd | Base directory for relative export/import paths |
| `PAC_VECTOR_LOG` | `WARNING` | Log level (stderr only) |

## Notes

- stdout is the JSON-RPC pipe: nothing may print to it. `tests/test_stdout_safety.py`
  scans the package for `print()` / `sys.stdout`, and `tests/test_stdio.py` runs a real session.
- Native modules are loaded before the stdio loop starts (`render.warm`): on Windows a
  first native load from inside the FastMCP loop can hang (see pac-pincers' `_excel.py`).
- Bounding boxes are measured from pixels (two-pass render), so they include strokes and
  filters and work for text and curves; content further than two page-widths off-canvas isn't found.
- Version lives only in `pyproject.toml`; a release is a commit named after the version.
