Initial commit

This commit is contained in:
U-C4N
2026-04-27 12:20:57 +03:00
commit 7b121ab416
49 changed files with 9904 additions and 0 deletions
@@ -0,0 +1,60 @@
# Architecture
## File Structure
```
server.py FastMCP 3.0 server — all tool/resource/prompt registrations
├── config.py Settings class (pydantic-settings, env vars)
├── security.py validate_path() + sanitize_command() + sanitize_lisp()
└── backends/
├── base.py AutoCADBackend ABC + data models
├── ezdxf_backend.py Headless DXF ops via ezdxf library
└── com_backend.py Live AutoCAD control via pywin32 COM
```
## Dual-Backend Strategy Pattern
`AutoCADBackend` (in `base.py`) is an abstract base class. Both backends implement the full interface. The server creates exactly one backend at startup via `_make_backend()`:
1. Check `AUTOCAD_MCP_BACKEND` env var
2. If `auto` or `com` on Windows: try COM → fall back to ezdxf
3. If non-Windows or `ezdxf`: use ezdxf
## Data Models
Defined in `base.py`:
- **EntityInfo**: `{handle, type, layer, color, linetype, visible, properties}`
- **LayerInfo**: `{name, color, linetype, lineweight, is_on, is_frozen, is_locked, is_current}`
- **BlockInfo**: `{name, origin, attribute_count, entity_count, is_xref, description}`
- **DrawingInfo**: `{name, full_path, saved, entity_count, layer_count, block_count, extents_min, extents_max, units, version, backend}`
- **CommandResult**: `{ok, payload, error}`
## Backend Differences
| Feature | ezdxf | COM |
|---------|-------|-----|
| Platform | Any | Windows only |
| AutoCAD needed | No | Yes (running) |
| View/zoom | No-op | Full control |
| Screenshots | matplotlib render | Win32 window capture |
| Commands/LISP | Not supported | Full support |
| Undo | DXF snapshot stack | Native AutoCAD undo |
| Threading | `asyncio.to_thread` via `_async()` | `ThreadPoolExecutor` (single thread, STA) |
| File formats | DXF only | DWG + DXF |
## FastMCP Server
The `mcp` object is configured with:
- **Lifespan**: `autocad_lifespan` — initializes backend, stores in `ctx.lifespan_context["backend"]`
- **Middleware**: ErrorHandling → AuditLog (custom timing) → Timing → Logging
- **`_backend(ctx)`**: Helper that retrieves backend from context, raises `ToolError` if unavailable
## Adding a New Tool
1. Add abstract method to `AutoCADBackend` in `backends/base.py`
2. Implement in `EzdxfBackend` — wrap sync calls with `_async(func)`
3. Implement in `ComBackend` — wrap COM calls with `self._com(func)`
4. Register in `server.py`: `@mcp.tool(...)` calling `_backend(ctx).method(...)`
5. Use `_dc(result)` to convert dataclass returns to dicts
6. Write tests in `tests/`
@@ -0,0 +1,53 @@
# Security
## Path Validation
All file-path tools pass through `validate_path()` in `security.py`.
**How it works**:
- Resolves path via `Path.resolve()` (removes `..`, symlinks)
- Checks against `ALLOWED_PATHS` env var (comma-separated directories)
- If `ALLOWED_PATHS` is empty → all paths allowed (backward compat)
- Separate `allow_write` flag for read vs write operations
**Tools with path validation**:
- `drawing_open` (read)
- `drawing_save`, `drawing_save_as` (write)
- `drawing_export_dxf`, `drawing_export_pdf` (write)
- `drawing_new` with template (read)
**Blocked examples**:
- `../../../etc/passwd` → rejected (traversal)
- `C:\Windows\System32\...` → rejected if not in ALLOWED_PATHS
- Relative paths with `..` → always rejected
## Command Sanitization
`sanitize_command()` checks `system_run_command` input:
**Blocked patterns**: `ERASE`, `DELETE`, `PURGE`, `QUIT`, `CLOSE`, `_QUIT`, shell-related commands
**Override**: Set `DANGEROUS_COMMANDS_ENABLED=true` to bypass.
## LISP Sanitization
`sanitize_lisp()` checks `system_run_lisp` input:
**Blocked functions**: `startapp`, `vl-file-delete`, `vl-file-rename`, `dos_*` (file system access), `command` with dangerous args
## Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| `ALLOWED_PATHS` | (empty) | Comma-separated allowed directories. Empty = all allowed |
| `DANGEROUS_COMMANDS_ENABLED` | `false` | Allow blocked commands |
| `AUTOCAD_MCP_BACKEND` | `auto` | Backend selection |
| `MAX_UNDO_STACK` | `50` | Max undo snapshots (ezdxf) |
| `LOG_LEVEL` | `INFO` | Logging level |
## Best Practices
- Always set `ALLOWED_PATHS` in production to restrict file access
- Never pass raw user input to `system_run_command` or `system_run_lisp`
- Use `transaction_begin/rollback` for destructive batch operations
- Review audit logs for suspicious tool calls (AuditMiddleware logs all calls)
@@ -0,0 +1,73 @@
# Analysis Tools (9)
Tools for querying and measuring drawing contents.
---
## analysis_entity_stats
No parameters. Returns entity counts grouped by type and by layer.
```json
{
"total": 150,
"by_type": {"LINE": 50, "CIRCLE": 20, "TEXT": 30, ...},
"by_layer": {"WALLS": 40, "DOORS": 10, ...}
}
```
## analysis_find_in_region
Find entities within a rectangular region.
| Param | Type | Description |
|-------|------|-------------|
| `x1, y1` | `float` | Region minimum corner |
| `x2, y2` | `float` | Region maximum corner |
| `type_filter` | `str \| null` | Filter by entity type |
Returns list of entity infos within the bounding box.
## analysis_measure_distance
Measure distance between two points.
| Param | Type | Description |
|-------|------|-------------|
| `x1, y1` | `float` | Point 1 |
| `x2, y2` | `float` | Point 2 |
Returns `{distance, dx, dy, angle}`.
## analysis_measure_area
Calculate area of a polygon.
| Param | Type | Description |
|-------|------|-------------|
| `points` | `list[list[float]]` | Polygon vertices (min 3 points) |
Returns `{area, perimeter, centroid}`.
## analysis_bounding_box
No parameters. Returns `{min_x, min_y, max_x, max_y, width, height}` for all entities.
## analysis_select_by_layer
Get all entities on a specific layer.
| Param | Type | Description |
|-------|------|-------------|
| `layer_name` | `str` | Layer to select from |
Returns list of entity infos.
## analysis_select_by_type
Get all entities of a specific type.
| Param | Type | Description |
|-------|------|-------------|
| `entity_type` | `str` | Type: LINE, CIRCLE, ARC, LWPOLYLINE, TEXT, MTEXT, INSERT, HATCH, SPLINE, ELLIPSE |
Returns list of entity infos.
## analysis_layer_stats
No parameters. Returns per-layer statistics: entity count, types present, color, state.
## analysis_entities_in_region
Alias/variant of `analysis_find_in_region` — check both for availability.
@@ -0,0 +1,83 @@
# Batch, Template & Validation Tools (5)
## Batch Operations
### entity_batch_create
Create multiple entities in a single call. Reports progress.
| Param | Type | Description |
|-------|------|-------------|
| `entities` | `list[dict]` | Entity definitions (see format below) |
Each dict requires `type` and type-specific params:
```json
[
{"type": "line", "x1": 0, "y1": 0, "x2": 100, "y2": 0},
{"type": "circle", "cx": 50, "cy": 50, "radius": 25},
{"type": "text", "text": "Hello", "x": 10, "y": 10, "height": 5},
{"type": "rectangle", "x1": 0, "y1": 0, "x2": 200, "y2": 100},
{"type": "point", "x": 75, "y": 75},
{"type": "arc", "cx": 50, "cy": 0, "radius": 10, "start_angle": 0, "end_angle": 180},
{"type": "polyline", "points": [[0,0],[10,10],[20,0]], "closed": true}
]
```
Optional per-entity: `layer`, `color`, `linetype`.
Returns `{created: [...handles], errors: [...]}`. Partial success is possible.
### entity_batch_modify
Apply multiple modifications in a single call. Reports progress.
| Param | Type | Description |
|-------|------|-------------|
| `operations` | `list[dict]` | Operation definitions |
Each dict requires `handle` and `action`:
```json
[
{"handle": "1A", "action": "move", "dx": 10, "dy": 20},
{"handle": "2B", "action": "rotate", "base_x": 0, "base_y": 0, "angle_deg": 45},
{"handle": "3C", "action": "scale", "base_x": 0, "base_y": 0, "factor": 2.0},
{"handle": "4D", "action": "delete"},
{"handle": "5E", "action": "set_properties", "layer": "WALLS", "color": 1}
]
```
Returns results per operation.
---
## Templates
### template_apply_layers
Apply a standard layer set to the current drawing.
| Param | Type | Description |
|-------|------|-------------|
| `template` | `str` | Template name: `architectural`, `mechanical`, `electrical`, `piping` |
Creates predefined layers with standard names, colors, and linetypes.
### template_list
No parameters. Returns all available templates and their layer definitions.
---
## Validation
### validation_check
Run quality checks on the drawing.
| Param | Type | Description |
|-------|------|-------------|
| `checks` | `list[str] \| null` | Check types (default: all) |
Available checks:
- `empty_layers` — Layers with no entities
- `zero_length` — Lines/arcs with zero length
- `duplicate_entities` — Overlapping identical entities
Returns `{issues: [{check, severity, message, details}, ...], summary}`.
@@ -0,0 +1,68 @@
# Block Operations Tools (7)
Blocks are reusable named groups of entities. A **block definition** is the template; a **block reference** (INSERT entity) is a placed instance with position, scale, and rotation.
---
## block_list
No parameters. Returns all block definitions: `{name, origin, attribute_count, entity_count, is_xref, description}`.
## block_insert
Place a block reference in the drawing.
| Param | Type | Description |
|-------|------|-------------|
| `name` | `str` | Block definition name (must exist) |
| `x, y` | `float` | Insertion point |
| `x_scale` | `float` | X scale factor (default: 1.0) |
| `y_scale` | `float` | Y scale factor (default: 1.0) |
| `rotation` | `float` | Rotation in degrees (default: 0) |
| `layer` | `str \| null` | Target layer |
Returns entity info with handle (type: INSERT).
## block_explode
Decompose a block reference into individual entities.
| Param | Type | Description |
|-------|------|-------------|
| `handle` | `str` | Block reference (INSERT entity) handle |
Returns list of new entity handles created from explosion.
## block_get_attributes
Read attribute values from a block reference.
| Param | Type | Description |
|-------|------|-------------|
| `handle` | `str` | Block reference handle |
Returns `{tag: value}` dict of all attributes.
## block_set_attributes
Write attribute values to a block reference.
| Param | Type | Description |
|-------|------|-------------|
| `handle` | `str` | Block reference handle |
| `attributes` | `dict` | `{tag: value}` pairs to set |
## block_create_from_entities
Create a new block definition from existing entities.
| Param | Type | Description |
|-------|------|-------------|
| `name` | `str` | New block definition name |
| `handles` | `list[str]` | Entity handles to include |
| `base_x, base_y` | `float` | Block base/insertion point |
Entities are moved into the block definition.
## block_find_references
Find all INSERT entities that reference a specific block.
| Param | Type | Description |
|-------|------|-------------|
| `name` | `str` | Block definition name |
Returns list of block reference entity infos.
@@ -0,0 +1,55 @@
# Dimension Tools (5)
All dimension tools return entity info with handle. Dimensions are placed on the current layer unless `layer` is specified.
---
## dimension_linear
Linear dimension between two points (horizontal or vertical measurement).
| Param | Type | Description |
|-------|------|-------------|
| `x1, y1` | `float` | First extension line origin |
| `x2, y2` | `float` | Second extension line origin |
| `dim_x, dim_y` | `float` | Dimension line position (controls placement) |
| `layer` | `str \| null` | Target layer |
## dimension_aligned
Aligned dimension — measures true distance between points regardless of angle.
| Param | Type | Description |
|-------|------|-------------|
| `x1, y1` | `float` | First point |
| `x2, y2` | `float` | Second point |
| `distance` | `float` | Offset distance for dimension line |
| `layer` | `str \| null` | Target layer |
## dimension_angular
Angular dimension between two lines meeting at a vertex.
| Param | Type | Description |
|-------|------|-------------|
| `vertex_x, vertex_y` | `float` | Angle vertex point |
| `start_x, start_y` | `float` | First line endpoint |
| `end_x, end_y` | `float` | Second line endpoint |
| `dim_x, dim_y` | `float` | Dimension arc position |
| `layer` | `str \| null` | Target layer |
## dimension_radius
Radius dimension for circles and arcs.
| Param | Type | Description |
|-------|------|-------------|
| `center_x, center_y` | `float` | Circle/arc center |
| `radius` | `float` | Radius value |
| `angle` | `float` | Leader angle in degrees (where arrow points) |
| `layer` | `str \| null` | Target layer |
## dimension_diameter
Diameter dimension across a circle.
| Param | Type | Description |
|-------|------|-------------|
| `x1, y1` | `float` | First point on diameter |
| `x2, y2` | `float` | Opposite point on diameter |
| `layer` | `str \| null` | Target layer |
@@ -0,0 +1,103 @@
# Drawing Management Tools (11)
## Contents
- [drawing_info](#drawing_info)
- [drawing_new](#drawing_new)
- [drawing_open](#drawing_open)
- [drawing_save](#drawing_save)
- [drawing_save_as](#drawing_save_as)
- [drawing_export_dxf](#drawing_export_dxf)
- [drawing_export_pdf](#drawing_export_pdf)
- [drawing_purge](#drawing_purge)
- [drawing_audit](#drawing_audit)
- [drawing_undo / drawing_redo](#drawing_undo--drawing_redo)
---
## drawing_info
Read-only. Returns comprehensive metadata for the current drawing.
**Returns**: `{name, full_path, saved, entity_count, layer_count, block_count, extents_min, extents_max, units, version, backend}`
---
## drawing_new
Create a new empty drawing, optionally from a template.
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `template` | `str \| null` | No | Path to `.dwt` template file |
Path validation applied to template. Returns drawing info dict.
---
## drawing_open
Open an existing DWG or DXF file. Reports progress.
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `path` | `str` | Yes | Full path to `.dwg` or `.dxf` file |
Path validation: `allow_write=False`. Returns drawing info dict.
---
## drawing_save
Save current drawing. Uses current path if omitted.
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `path` | `str \| null` | No | Optional save path |
Path validation: `allow_write=True`.
---
## drawing_save_as
Save drawing to a new path.
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `path` | `str` | Yes | Full destination path with extension |
Path validation: `allow_write=True`.
---
## drawing_export_dxf
Export drawing as DXF file.
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `path` | `str` | Yes | Output `.dxf` file path |
| `version` | `str` | No | DXF version: `R2010`, `R2013`, `R2018` (default: `R2018`) |
---
## drawing_export_pdf
Export drawing as PDF. Requires `matplotlib`.
| Param | Type | Required | Description |
|-------|------|----------|-------------|
| `path` | `str` | Yes | Output `.pdf` file path |
---
## drawing_purge
Remove all unused objects (layers, blocks, linetypes, styles). No parameters.
---
## drawing_audit
Run integrity audit — detect and fix drawing errors. No parameters.
---
## drawing_undo / drawing_redo
Undo/redo last operation.
- **ezdxf**: Snapshot-based (restores full DXF state from `_undo_stack`)
- **COM**: Native AutoCAD undo/redo
**Note**: For multi-step undo protection, use `transaction_begin/rollback` instead.
@@ -0,0 +1,96 @@
# Entity Creation Tools (13)
All creation tools return `{handle, type, layer, color, linetype, visible, properties}`. The `handle` (hex string) is required for all subsequent operations on that entity.
Common optional params on all creation tools:
| Param | Type | Default | Description |
|-------|------|---------|-------------|
| `layer` | `str` | Current layer | Target layer name |
| `color` | `int` | 256 (ByLayer) | ACI color (1-255, 256=ByLayer, 0=ByBlock) |
| `linetype` | `str` | `"ByLayer"` | Linetype name |
---
## entity_create_line
| Param | Type | Description |
|-------|------|-------------|
| `x1, y1` | `float` | Start point |
| `x2, y2` | `float` | End point |
## entity_create_circle
| Param | Type | Description |
|-------|------|-------------|
| `cx, cy` | `float` | Center point |
| `radius` | `float` | Radius |
## entity_create_arc
| Param | Type | Description |
|-------|------|-------------|
| `cx, cy` | `float` | Center point |
| `radius` | `float` | Radius |
| `start_angle` | `float` | Start angle (degrees, CCW from X) |
| `end_angle` | `float` | End angle (degrees) |
## entity_create_polyline
| Param | Type | Description |
|-------|------|-------------|
| `points` | `list[list[float]]` | `[[x,y], [x,y], ...]` coordinate pairs |
| `closed` | `bool` | Close the polyline (default: false) |
## entity_create_rectangle
| Param | Type | Description |
|-------|------|-------------|
| `x1, y1` | `float` | First corner |
| `x2, y2` | `float` | Opposite corner |
Creates an LWPOLYLINE (closed).
## entity_create_text
| Param | Type | Description |
|-------|------|-------------|
| `text` | `str` | Text content |
| `x, y` | `float` | Insertion point |
| `height` | `float` | Text height (default: 2.5) |
| `rotation` | `float` | Rotation angle in degrees (default: 0) |
## entity_create_mtext
| Param | Type | Description |
|-------|------|-------------|
| `text` | `str` | Content (`\P` for paragraph break, `{\H...;}` for formatting) |
| `x, y` | `float` | Insertion point |
| `width` | `float` | Text box width (default: 100) |
| `height` | `float` | Character height (default: 2.5) |
## entity_create_hatch
| Param | Type | Description |
|-------|------|-------------|
| `pattern` | `str` | Pattern name: `SOLID`, `ANSI31`, `ANSI32`, `STEEL`, `GRAVEL`, etc. |
| `boundary_points` | `list[list[float]]` | Closed boundary polygon `[[x,y], ...]` |
| `scale` | `float` | Pattern scale (default: 1.0) |
| `angle` | `float` | Pattern angle (default: 0) |
## entity_create_spline
| Param | Type | Description |
|-------|------|-------------|
| `fit_points` | `list[list[float]]` | Points the spline passes through |
## entity_create_ellipse
| Param | Type | Description |
|-------|------|-------------|
| `cx, cy` | `float` | Center point |
| `major_axis_x, major_axis_y` | `float` | Major axis endpoint (relative to center) |
| `ratio` | `float` | Minor/major axis ratio (0.0–1.0) |
## entity_create_point
| Param | Type | Description |
|-------|------|-------------|
| `x, y` | `float` | Point coordinates |
## entity_create_block_ref
| Param | Type | Description |
|-------|------|-------------|
| `name` | `str` | Block definition name (must exist) |
| `x, y` | `float` | Insertion point |
| `x_scale, y_scale` | `float` | Scale factors (default: 1.0) |
| `rotation` | `float` | Rotation in degrees (default: 0) |
@@ -0,0 +1,111 @@
# Entity Modification & Query Tools (13)
All modify tools require a `handle` (hex string). Get handles from `entity_list()` or any `entity_create_*` return value.
---
## Modification Tools (10)
### entity_move
| Param | Type | Description |
|-------|------|-------------|
| `handle` | `str` | Entity handle |
| `dx, dy` | `float` | Displacement vector |
### entity_copy
Returns new entity info with a **new handle**.
| Param | Type | Description |
|-------|------|-------------|
| `handle` | `str` | Entity to copy |
| `dx, dy` | `float` | Offset for the copy |
### entity_rotate
| Param | Type | Description |
|-------|------|-------------|
| `handle` | `str` | Entity handle |
| `base_x, base_y` | `float` | Rotation base point |
| `angle_degrees` | `float` | Rotation angle (CCW) |
### entity_scale
| Param | Type | Description |
|-------|------|-------------|
| `handle` | `str` | Entity handle |
| `base_x, base_y` | `float` | Scale base point |
| `factor` | `float` | Scale factor |
### entity_mirror
| Param | Type | Description |
|-------|------|-------------|
| `handle` | `str` | Entity handle |
| `x1, y1` | `float` | Mirror line point 1 |
| `x2, y2` | `float` | Mirror line point 2 |
### entity_offset
Works on line, circle, polyline.
| Param | Type | Description |
|-------|------|-------------|
| `handle` | `str` | Entity handle |
| `distance` | `float` | Offset distance (positive = outward) |
### entity_delete
| Param | Type | Description |
|-------|------|-------------|
| `handle` | `str` | Entity to delete |
### entity_array_rectangular
| Param | Type | Description |
|-------|------|-------------|
| `handle` | `str` | Entity to array |
| `rows` | `int` | Number of rows |
| `cols` | `int` | Number of columns |
| `row_spacing` | `float` | Row spacing |
| `col_spacing` | `float` | Column spacing |
Returns list of new entity handles.
### entity_array_polar
| Param | Type | Description |
|-------|------|-------------|
| `handle` | `str` | Entity to array |
| `center_x, center_y` | `float` | Array center point |
| `count` | `int` | Number of copies |
| `angle` | `float` | Total angle to fill (degrees, default: 360) |
### entity_set_properties
| Param | Type | Description |
|-------|------|-------------|
| `handle` | `str` | Entity handle |
| `layer` | `str \| null` | Move to layer |
| `color` | `int \| null` | Change ACI color |
| `linetype` | `str \| null` | Change linetype |
| `lineweight` | `float \| null` | Change lineweight |
All property params are optional — only provided ones are changed.
---
## Query Tools (3)
### entity_get
| Param | Type | Description |
|-------|------|-------------|
| `handle` | `str` | Entity handle |
Returns full entity info: `{handle, type, layer, color, linetype, visible, properties}`.
### entity_list
| Param | Type | Description |
|-------|------|-------------|
| `type_filter` | `str \| null` | Filter: `LINE`, `CIRCLE`, `ARC`, `LWPOLYLINE`, `TEXT`, `MTEXT`, `INSERT`, `HATCH`, etc. |
| `layer_filter` | `str \| null` | Filter by layer name |
| `limit` | `int` | Max results (default: 100) |
| `offset` | `int` | Skip first N results (default: 0) |
### entity_delete_many
| Param | Type | Description |
|-------|------|-------------|
| `handles` | `list[str]` | List of handles to delete |
Reports progress. Returns `{deleted, failed, errors}`.
@@ -0,0 +1,63 @@
# Layer Management Tools (12)
Layers organize entities by category (walls, doors, dimensions, etc.). Each layer has: name, color (ACI), linetype, lineweight, and states (on/off, frozen/thawed, locked/unlocked).
---
## layer_list
No parameters. Returns list of all layers with properties: `{name, color, linetype, lineweight, is_on, is_frozen, is_locked, is_current}`.
## layer_create
| Param | Type | Description |
|-------|------|-------------|
| `name` | `str` | New layer name |
| `color` | `int` | ACI color (default: 7=white) |
| `linetype` | `str` | Linetype name (default: `"Continuous"`) |
## layer_delete
| Param | Type | Description |
|-------|------|-------------|
| `name` | `str` | Layer to delete (must be empty, cannot be layer "0") |
## layer_set_current
| Param | Type | Description |
|-------|------|-------------|
| `name` | `str` | Layer to make current (new entities go here) |
## layer_modify
| Param | Type | Description |
|-------|------|-------------|
| `name` | `str` | Layer to modify |
| `color` | `int \| null` | New color |
| `linetype` | `str \| null` | New linetype |
| `lineweight` | `float \| null` | New lineweight |
## layer_freeze / layer_thaw
Freeze hides and excludes from regeneration (faster). Thaw restores.
| Param | Type | Description |
|-------|------|-------------|
| `name` | `str` | Layer name |
## layer_lock / layer_unlock
Lock prevents editing but keeps visible. Unlock restores editing.
| Param | Type | Description |
|-------|------|-------------|
| `name` | `str` | Layer name |
## layer_hide / layer_show
Hide turns layer off (invisible). Show turns it on.
| Param | Type | Description |
|-------|------|-------------|
| `name` | `str` | Layer name |
## layer_isolate
Shows only the specified layer, hides all others.
| Param | Type | Description |
|-------|------|-------------|
| `name` | `str` | Layer to keep visible |
To restore: `layer_show` each hidden layer, or reopen the drawing.
@@ -0,0 +1,95 @@
# View, Transaction & System Tools (14)
## View & Screenshot (5)
### view_zoom_extents
Zoom to show all entities. No parameters. **COM only** (no-op in ezdxf).
### view_zoom_window
Zoom to a specific rectangular area. **COM only**.
| Param | Type | Description |
|-------|------|-------------|
| `x1, y1` | `float` | Window corner 1 |
| `x2, y2` | `float` | Window corner 2 |
### view_screenshot
Capture drawing as image. Returns base64-encoded image.
- **COM**: Win32 window capture (requires Pillow)
- **ezdxf**: matplotlib render (requires matplotlib)
### view_zoom_and_screenshot
Combined zoom + screenshot in one call.
| Param | Type | Description |
|-------|------|-------------|
| `x1, y1` | `float \| null` | Optional zoom window corner 1 |
| `x2, y2` | `float \| null` | Optional zoom window corner 2 |
If coordinates omitted, captures full extents.
### view_set_view
Set named view. Parameters depend on backend.
---
## Transactions (3)
Use transactions to group operations with undo support.
```
transaction_begin() # Save checkpoint
... make changes ...
transaction_commit() # Accept changes
# or
transaction_rollback() # Revert to checkpoint
```
### transaction_begin
Start a transaction. ezdxf saves full DXF snapshot; COM creates undo mark.
### transaction_commit
Accept all changes since `transaction_begin`.
### transaction_rollback
Revert all changes since `transaction_begin`. ezdxf restores snapshot; COM uses native undo.
---
## System (6)
### system_status
No parameters. Returns server status: `{backend, drawing_loaded, entity_count, uptime, ...}`.
### system_get_variable
| Param | Type | Description |
|-------|------|-------------|
| `name` | `str` | Variable name: `DIMSCALE`, `LTSCALE`, `INSUNITS`, `CLAYER`, `MEASUREMENT` |
### system_set_variable
| Param | Type | Description |
|-------|------|-------------|
| `name` | `str` | Variable name |
| `value` | `any` | New value |
### system_run_command
Execute raw AutoCAD command. **COM only**. Sanitized by `sanitize_command()`.
| Param | Type | Description |
|-------|------|-------------|
| `command` | `str` | Command string (e.g. `_ZOOM E`, `_REGEN`) |
Dangerous commands blocked unless `DANGEROUS_COMMANDS_ENABLED=true`.
### system_run_lisp
Evaluate AutoLISP expression. **COM only**. Sanitized by `sanitize_lisp()`.
| Param | Type | Description |
|-------|------|-------------|
| `expression` | `str` | LISP expression (e.g. `(command "ZOOM" "E")`) |
Dangerous functions blocked: `startapp`, `vl-file-delete`, `dos_*`.
### system_about
No parameters. Returns server capabilities, tool count, version, and feature list.
@@ -0,0 +1,79 @@
# Troubleshooting
## Common Errors
### "AutoCAD backend unavailable"
**Cause**: No drawing is loaded — backend needs an active drawing context.
**Fix**: Call `drawing_new()` or `drawing_open(path)` before any other operations.
### "Entity handle 'XXXX' not found"
**Cause**: Handle doesn't exist, was deleted, or drawing was reloaded.
**Fix**: Use `entity_list()` to get current valid handles. Handles are session-specific in ezdxf; persist by saving/reopening.
### "Layer 'X' not found"
**Cause**: Layer doesn't exist in the drawing.
**Fix**: `layer_list()` to see existing layers. `layer_create("X")` to create it.
### "Cannot delete layer '0'"
**Cause**: Layer "0" is the default layer and cannot be removed.
**Fix**: Move entities to another layer instead. Layer "0" always exists.
### "Path validation failed"
**Cause**: Path contains traversal (`..`) or is outside `ALLOWED_PATHS`.
**Fix**: Use absolute paths within configured allowed directories. Check `ALLOWED_PATHS` env var.
### "Command rejected by sanitizer"
**Cause**: `system_run_command` detected a dangerous pattern (ERASE, DELETE, etc.).
**Fix**: Use specific tools instead (e.g., `entity_delete` instead of `ERASE` command). Or set `DANGEROUS_COMMANDS_ENABLED=true` if needed.
### "LISP expression rejected"
**Cause**: `system_run_lisp` detected dangerous function (startapp, file ops).
**Fix**: Use MCP tools instead of LISP for file operations.
### "COM backend initialization failed"
**Cause**: AutoCAD not running, not installed, or COM registration issues.
**Fix**: Start AutoCAD, then retry. Or switch to ezdxf: `AUTOCAD_MCP_BACKEND=ezdxf`.
### "View operations are no-ops"
**Cause**: Using ezdxf backend — view/zoom commands only work with COM.
**Fix**: Switch to COM backend if live viewport control is needed. Screenshots still work via matplotlib in ezdxf.
### "Screenshot failed"
**Cause**: Missing dependency (Pillow for COM, matplotlib for ezdxf).
**Fix**: `pip install Pillow` (COM) or `pip install matplotlib` (ezdxf).
### "PDF export failed"
**Cause**: matplotlib not installed.
**Fix**: `pip install matplotlib` or `pip install -e ".[pdf]"`.
### "Transaction not active"
**Cause**: `transaction_commit/rollback` called without `transaction_begin`.
**Fix**: Always call `transaction_begin()` first.
### "Block 'X' not found"
**Cause**: Block definition doesn't exist.
**Fix**: `block_list()` to see available blocks. Create a block with `block_create_from_entities()`.
---
## Backend-Specific Issues
### ezdxf Backend
- **No DWG write support**: ezdxf reads DWG but can only write DXF. Use `drawing_export_dxf()`.
- **Undo stack memory**: Full DXF snapshots stored. `MAX_UNDO_STACK` env limits count (default: 50).
- **Text rendering**: Depends on system fonts. MathTex/complex formatting may not render in screenshots.
### COM Backend
- **STA threading**: All COM calls go through a single thread. Batch operations are sequential.
- **AutoCAD version**: Tested with AutoCAD 2020+. Older versions may have COM API differences.
- **Window capture**: Screenshots capture the AutoCAD window as-is. Minimize overlapping windows.
---
## Diagnostic Steps
1. `system_status()` — Check backend type, connection, drawing state
2. `system_about()` — See available tools and capabilities
3. `drawing_info()` — Verify drawing is loaded and get metadata
4. `analysis_entity_stats()` — Quick overview of drawing contents
5. Check logs: `LOG_LEVEL=DEBUG` for verbose output
@@ -0,0 +1,166 @@
# Common Workflows
## 1. New Drawing from Scratch
```
Progress:
- [ ] Step 1: Create drawing
- [ ] Step 2: Set up layers
- [ ] Step 3: Draw entities
- [ ] Step 4: Add dimensions
- [ ] Step 5: Add text annotations
- [ ] Step 6: Verify and save
```
**Step 1**: `drawing_new()` — creates empty drawing
**Step 2**: Create layers for organization:
```
layer_create("WALLS", color=7, linetype="Continuous")
layer_create("DOORS", color=3)
layer_create("WINDOWS", color=5)
layer_create("DIMENSIONS", color=1)
layer_create("TEXT", color=2)
```
Or use `template_apply_layers("architectural")` for standard sets.
**Step 3**: Draw geometry on appropriate layers:
```
layer_set_current("WALLS")
entity_create_rectangle(x1=0, y1=0, x2=6000, y2=4000)
entity_create_line(x1=3000, y1=0, x2=3000, y2=4000)
```
**Step 4**: Add dimensions:
```
layer_set_current("DIMENSIONS")
dimension_linear(x1=0, y1=0, x2=6000, y2=0, dim_x=3000, dim_y=-500)
```
**Step 5**: Add text labels:
```
layer_set_current("TEXT")
entity_create_text(text="Living Room", x=1500, y=2000, height=200)
```
**Step 6**: Verify and save:
```
analysis_entity_stats() # check entity counts
validation_check() # run quality checks
drawing_save("/path/to/drawing.dxf")
```
---
## 2. Edit Existing DXF
```
Progress:
- [ ] Step 1: Open file
- [ ] Step 2: Explore contents
- [ ] Step 3: Make changes (with transaction)
- [ ] Step 4: Verify and save
```
**Step 1**: `drawing_open("/path/to/file.dxf")`
**Step 2**: Explore:
```
analysis_entity_stats() # overview
layer_list() # see layers
entity_list(type_filter="LINE", limit=20) # browse entities
```
**Step 3**: Begin transaction, then modify:
```
transaction_begin()
entity_move(handle="1A2B", dx=100, dy=0)
entity_set_properties(handle="3C4D", color=1, layer="WALLS")
entity_delete(handle="5E6F")
transaction_commit() # or transaction_rollback() to undo all
```
**Step 4**: `drawing_save()`
---
## 3. Batch Entity Creation
```
Progress:
- [ ] Step 1: Prepare entity list
- [ ] Step 2: Batch create
- [ ] Step 3: Verify results
```
**Step 1**: Build entity definitions:
```json
[
{"type": "line", "x1": 0, "y1": 0, "x2": 100, "y2": 0, "layer": "WALLS"},
{"type": "line", "x1": 100, "y1": 0, "x2": 100, "y2": 100, "layer": "WALLS"},
{"type": "circle", "cx": 50, "cy": 50, "radius": 10, "layer": "DETAILS"},
{"type": "text", "text": "A1", "x": 50, "y": -20, "height": 5, "layer": "TEXT"}
]
```
**Step 2**: `entity_batch_create(entities=[...])` — returns handles for all created entities
**Step 3**: `analysis_entity_stats()` to verify counts
---
## 4. Drawing Analysis
```
Progress:
- [ ] Step 1: Open drawing
- [ ] Step 2: Get overview stats
- [ ] Step 3: Examine specific areas
- [ ] Step 4: Measure and report
```
**Step 1**: `drawing_open(path)` or `drawing_info()` if already open
**Step 2**:
```
analysis_entity_stats() # by type and layer
analysis_layer_stats() # per-layer details
analysis_bounding_box() # drawing extents
```
**Step 3**: Region queries:
```
analysis_find_in_region(x1=0, y1=0, x2=1000, y2=1000, type_filter="LINE")
analysis_select_by_layer(layer_name="WALLS")
analysis_select_by_type(entity_type="CIRCLE")
```
**Step 4**: Measurements:
```
analysis_measure_distance(x1=0, y1=0, x2=100, y2=100)
analysis_measure_area(points=[[0,0],[100,0],[100,100],[0,100]])
```
---
## 5. Template-Based Drawing
```
Progress:
- [ ] Step 1: Create drawing with template
- [ ] Step 2: Apply layer standards
- [ ] Step 3: Add content
- [ ] Step 4: Validate and save
```
**Step 1**: `drawing_new(template="/path/to/template.dwt")` (or `drawing_new()` without template)
**Step 2**: `template_apply_layers("architectural")` — creates standard layers
**Step 3**: Draw content on appropriate layers
**Step 4**:
```
validation_check(["empty_layers", "zero_length"])
drawing_save("/path/to/output.dxf")
```