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
+156
View File
@@ -0,0 +1,156 @@
---
name: autocad-mcp
description: |
Automate AutoCAD drawing operations through AutoCAD MCP Pro server (FastMCP 3.0).
86 tools for drawings, entities, layers, blocks, dimensions, analysis, batch ops,
templates, and validation. Dual backends: COM (live AutoCAD) and ezdxf (headless DXF).
Trigger when: (1) User mentions AutoCAD, DXF, DWG, or CAD drawings,
(2) User wants to create/modify engineering drawings programmatically,
(3) Working with tools prefixed drawing_, entity_, layer_, block_, dimension_,
analysis_, view_, system_, template_, or validation_,
(4) User asks about CAD automation, drafting workflows, or MCP server setup.
---
# AutoCAD MCP Pro
## Contents
- [Quick Start](#quick-start)
- [Backend Selection](#backend-selection)
- [Key Concepts](#key-concepts)
- [Tool Groups](#tool-groups)
- [Common Workflows](#common-workflows)
- [Security Rules](#security-rules)
- [Architecture](#architecture)
- [Troubleshooting](#troubleshooting)
- [Examples](#examples)
## Quick Start
Standard workflow for any drawing task:
```
1. drawing_new() # or drawing_open(path)
2. layer_create(name, color, linetype) # set up layers
3. entity_create_*(...) # draw geometry
4. dimension_*(...) # add dimensions
5. analysis_entity_stats() # verify drawing
6. drawing_save() # persist changes
```
Use `transaction_begin()` before complex operations. If something goes wrong, `transaction_rollback()` reverts all changes since begin.
For batch operations, use `entity_batch_create(entities)` with a list of entity definitions — handles are returned for each created entity.
## Backend Selection
| Environment Variable | Behavior |
|---------------------|----------|
| `AUTOCAD_MCP_BACKEND=auto` | Try COM first, fall back to ezdxf (default) |
| `AUTOCAD_MCP_BACKEND=com` | Force COM — requires running AutoCAD on Windows |
| `AUTOCAD_MCP_BACKEND=ezdxf` | Force ezdxf — headless DXF ops, no AutoCAD needed |
COM-only features: `system_run_command`, `system_run_lisp`, `view_zoom_extents/window` (view ops are no-ops in ezdxf). Screenshots: COM uses Win32 capture, ezdxf uses matplotlib render.
## Key Concepts
**Entity handles**: Hex strings (e.g. `"1A2B"`) returned by all create/copy operations. Required for modify/query operations (`entity_get`, `entity_move`, `entity_delete`, etc.).
**Coordinates**: Drawing units (mm default). Angles in degrees, counter-clockwise from X axis.
**ACI colors**: 1–255 = specific colors, 256 = ByLayer, 0 = ByBlock. Common: 1=red, 2=yellow, 3=green, 4=cyan, 5=blue, 6=magenta, 7=white.
**Transactions**: `transaction_begin` → operations → `transaction_commit` or `transaction_rollback`. ezdxf uses full DXF snapshots; COM uses native undo marks.
## Tool Groups
| Group | Count | Key Tools | Details |
|-------|-------|-----------|---------|
| Drawing Management | 11 | `drawing_new`, `drawing_open`, `drawing_save`, `drawing_export_*` | [tools-drawing.md](references/tools-drawing.md) |
| Entity Creation | 13 | `entity_create_line/circle/arc/polyline/text/hatch/...` | [tools-entity-creation.md](references/tools-entity-creation.md) |
| Entity Modification | 13 | `entity_move/copy/rotate/scale/mirror/offset/delete/...` | [tools-entity-modification.md](references/tools-entity-modification.md) |
| Dimensions | 5 | `dimension_linear/aligned/angular/radius/diameter` | [tools-dimensions.md](references/tools-dimensions.md) |
| Layer Management | 12 | `layer_create/delete/freeze/thaw/lock/unlock/isolate/...` | [tools-layers.md](references/tools-layers.md) |
| Block Operations | 7 | `block_insert/explode/create_from_entities/attributes/...` | [tools-blocks.md](references/tools-blocks.md) |
| Analysis | 9 | `analysis_entity_stats/find_in_region/measure_*/bounding_box` | [tools-analysis.md](references/tools-analysis.md) |
| Batch & Templates | 4 | `entity_batch_create/modify`, `template_apply_layers/list` | [tools-batch-template.md](references/tools-batch-template.md) |
| Validation | 1 | `validation_check` | [tools-batch-template.md](references/tools-batch-template.md) |
| View & Screenshot | 5 | `view_zoom_extents/window/screenshot/zoom_and_screenshot` | [tools-view-system.md](references/tools-view-system.md) |
| Transactions | 3 | `transaction_begin/commit/rollback` | [tools-view-system.md](references/tools-view-system.md) |
| System | 6 | `system_status/get_variable/run_command/run_lisp/about` | [tools-view-system.md](references/tools-view-system.md) |
**Resources** (6): `autocad://drawing`, `autocad://layers`, `autocad://blocks`, `autocad://stats`, `autocad://status`, `autocad://entities/{layer_name}`
**Prompt templates** (5): `prompt_floor_plan`, `prompt_pid_diagram`, `prompt_electrical_schematic`, `prompt_mechanical_drawing`, `prompt_quick_drawing`
## Common Workflows
**New drawing from scratch**: Set up layers first, then draw entities, add dimensions, save.
See [workflows.md](references/workflows.md) for step-by-step checklists.
**Edit existing DXF**: `drawing_open` → `entity_list` to find entities → modify/delete → save.
**Batch operations**: `entity_batch_create([{type:"line", ...}, {type:"circle", ...}])` — single call, multiple entities.
**Template-based**: `template_apply_layers("architectural")` creates standard layer sets, then add content.
**Quality check**: `validation_check(["empty_layers", "zero_length", "duplicate_entities"])` reports issues.
## Security Rules
All file paths pass through `validate_path()`:
- Path traversal blocked (`../` patterns rejected)
- `ALLOWED_PATHS` env restricts accessible directories
- Write operations require `allow_write=True`
Commands pass through `sanitize_command()`:
- Dangerous patterns blocked: ERASE ALL, DELETE, PURGE, QUIT
- LISP sanitized: `startapp`, `vl-file-delete`, `dos_*` rejected
- Override: `DANGEROUS_COMMANDS_ENABLED=true`
Details: [security.md](references/security.md)
## Architecture
```
server.py FastMCP 3.0 server (86 tools, 6 resources, 5 prompts)
├── config.py Centralized pydantic-settings configuration
├── security.py Path validation + command sanitization
└── backends/
├── base.py AutoCADBackend ABC + data models
├── ezdxf_backend.py Headless DXF via ezdxf (async via _async wrapper)
└── com_backend.py Live AutoCAD via pywin32 COM (STA single-thread)
```
Middleware stack: ErrorHandling → AuditLog → Timing → Logging
Adding a new tool: (1) abstract method in `base.py` → (2) implement in `ezdxf_backend.py` → (3) implement in `com_backend.py` → (4) register in `server.py` with `@mcp.tool` → (5) test
Details: [architecture.md](references/architecture.md)
## Troubleshooting
| Error | Solution |
|-------|----------|
| "Backend unavailable" | Call `drawing_new()` or `drawing_open(path)` first |
| "Entity handle not found" | Use `entity_list()` to get valid handles |
| "Layer not found" | `layer_list()` to see existing, `layer_create()` to add |
| "Path validation failed" | Use absolute paths within `ALLOWED_PATHS` |
| "Command rejected" | Check `DANGEROUS_COMMANDS_ENABLED` setting |
| "COM backend failed" | Verify AutoCAD is running, or switch to ezdxf |
| "View ops are no-ops" | View/zoom only work with COM backend |
Full list: [troubleshooting.md](references/troubleshooting.md)
## Examples
- [Basic drawing workflow](examples/basic-workflow.md) — Room with walls, door, dimensions
- [Floor plan](examples/floor-plan.md) — Multi-room apartment layout
- [Mechanical part](examples/mechanical-part.md) — Flange with bolt pattern
## Utility Scripts
**Setup check**: `python scripts/check_setup.py` — Verify dependencies and configuration
**Drawing validation**: `python scripts/validate_drawing.py` — Check for common drawing issues
@@ -0,0 +1,50 @@
{
"architectural": {
"description": "Standard architectural drawing layers",
"layers": [
{"name": "WALLS", "color": 7, "linetype": "Continuous", "description": "Wall outlines"},
{"name": "DOORS", "color": 3, "linetype": "Continuous", "description": "Door swings and frames"},
{"name": "WINDOWS", "color": 5, "linetype": "Continuous", "description": "Window openings"},
{"name": "DIMENSIONS", "color": 1, "linetype": "Continuous", "description": "Dimension annotations"},
{"name": "TEXT", "color": 2, "linetype": "Continuous", "description": "Text labels and notes"},
{"name": "FURNITURE", "color": 8, "linetype": "Continuous", "description": "Furniture outlines"},
{"name": "PLUMBING", "color": 4, "linetype": "Continuous", "description": "Plumbing fixtures"},
{"name": "HVAC", "color": 6, "linetype": "Continuous", "description": "HVAC equipment and ducts"}
]
},
"mechanical": {
"description": "Standard mechanical drawing layers",
"layers": [
{"name": "OUTLINE", "color": 7, "linetype": "Continuous", "description": "Part outlines"},
{"name": "CENTERLINE", "color": 1, "linetype": "CENTER", "description": "Center lines and axes"},
{"name": "HIDDEN", "color": 8, "linetype": "HIDDEN", "description": "Hidden edges"},
{"name": "DIMENSIONS", "color": 5, "linetype": "Continuous", "description": "Dimensions"},
{"name": "NOTES", "color": 2, "linetype": "Continuous", "description": "Notes and callouts"},
{"name": "SECTION", "color": 3, "linetype": "Continuous", "description": "Section lines and hatching"},
{"name": "DETAIL", "color": 4, "linetype": "Continuous", "description": "Detail views"}
]
},
"electrical": {
"description": "Standard electrical drawing layers",
"layers": [
{"name": "POWER", "color": 1, "linetype": "Continuous", "description": "Power circuits"},
{"name": "LIGHTING", "color": 2, "linetype": "Continuous", "description": "Lighting circuits"},
{"name": "DATA", "color": 3, "linetype": "Continuous", "description": "Data and communication"},
{"name": "FIRE_ALARM", "color": 4, "linetype": "Continuous", "description": "Fire alarm system"},
{"name": "HVAC_CTRL", "color": 5, "linetype": "Continuous", "description": "HVAC controls"},
{"name": "PANELS", "color": 7, "linetype": "Continuous", "description": "Panel boards and equipment"},
{"name": "CONDUIT", "color": 8, "linetype": "Continuous", "description": "Conduit runs"}
]
},
"piping": {
"description": "Standard piping/P&ID drawing layers",
"layers": [
{"name": "PROCESS", "color": 7, "linetype": "Continuous", "description": "Process piping"},
{"name": "UTILITY", "color": 3, "linetype": "Continuous", "description": "Utility piping"},
{"name": "INSTRUMENTS", "color": 1, "linetype": "Continuous", "description": "Instrumentation"},
{"name": "EQUIPMENT", "color": 5, "linetype": "Continuous", "description": "Equipment outlines"},
{"name": "VALVES", "color": 2, "linetype": "Continuous", "description": "Valves and fittings"},
{"name": "LABELS", "color": 4, "linetype": "Continuous", "description": "Labels and tags"}
]
}
}
@@ -0,0 +1,72 @@
# Example: Basic Room Drawing
Create a simple room with walls, a door opening, dimensions, and labels.
## Setup
```
drawing_new()
layer_create("WALLS", color=7)
layer_create("DOORS", color=3)
layer_create("DIMENSIONS", color=1)
layer_create("TEXT", color=2)
```
## Draw Walls (5m x 4m room)
```
layer_set_current("WALLS")
# Outer walls as rectangle
entity_create_rectangle(x1=0, y1=0, x2=5000, y2=4000)
# Returns: {handle: "A1", type: "LWPOLYLINE", ...}
```
## Add Door Opening (0.9m wide on south wall)
```
layer_set_current("DOORS")
# Door opening represented as an arc (90° swing)
entity_create_arc(cx=2000, cy=0, radius=900, start_angle=0, end_angle=90)
# Returns: {handle: "B2", type: "ARC", ...}
# Door frame lines
entity_create_line(x1=2000, y1=0, x2=2000, y2=100)
entity_create_line(x1=2900, y1=0, x2=2900, y2=100)
```
## Add Dimensions
```
layer_set_current("DIMENSIONS")
# Room width
dimension_linear(x1=0, y1=0, x2=5000, y2=0, dim_x=2500, dim_y=-500)
# Room height
dimension_linear(x1=5000, y1=0, x2=5000, y2=4000, dim_x=5500, dim_y=2000)
# Door width
dimension_linear(x1=2000, y1=0, x2=2900, y2=0, dim_x=2450, dim_y=-300)
```
## Add Labels
```
layer_set_current("TEXT")
entity_create_text(text="BEDROOM", x=2500, y=2000, height=200)
entity_create_text(text="5000", x=2500, y=-800, height=150)
```
## Verify and Save
```
analysis_entity_stats()
# Expected: ~8 entities across 4 layers
validation_check(["empty_layers"])
# Should report no issues
drawing_save("C:/drawings/room.dxf")
```
@@ -0,0 +1,100 @@
# Example: Apartment Floor Plan
Create a 3-room apartment: living room, bedroom, kitchen with doors and windows.
## Setup
```
drawing_new()
template_apply_layers("architectural")
# Creates: WALLS, DOORS, WINDOWS, DIMENSIONS, TEXT, FURNITURE, PLUMBING, HVAC
```
## Draw Exterior Walls (12m x 8m)
```
layer_set_current("WALLS")
# Exterior boundary
entity_create_rectangle(x1=0, y1=0, x2=12000, y2=8000)
```
## Draw Interior Walls
```
# Living/bedroom divider (vertical at x=5000)
entity_create_line(x1=5000, y1=0, x2=5000, y2=8000)
# Kitchen divider (horizontal at y=4000, from x=5000)
entity_create_line(x1=5000, y1=4000, x2=12000, y2=4000)
```
## Add Doors (0.9m openings)
```
layer_set_current("DOORS")
# Living room door (south wall)
entity_create_arc(cx=2000, cy=0, radius=900, start_angle=0, end_angle=90)
# Bedroom door (on divider wall)
entity_create_arc(cx=5000, cy=2000, radius=900, start_angle=90, end_angle=180)
# Kitchen door (on divider wall)
entity_create_arc(cx=7000, cy=4000, radius=900, start_angle=0, end_angle=90)
```
## Add Windows (1.5m wide)
```
layer_set_current("WINDOWS")
# Living room window (north wall)
entity_create_line(x1=1500, y1=8000, x2=3000, y2=8000, color=5)
# Bedroom window (east wall)
entity_create_line(x1=12000, y1=5500, x2=12000, y2=7000, color=5)
# Kitchen window (east wall)
entity_create_line(x1=12000, y1=1500, x2=12000, y2=3000, color=5)
```
## Add Dimensions
```
layer_set_current("DIMENSIONS")
# Overall width
dimension_linear(x1=0, y1=0, x2=12000, y2=0, dim_x=6000, dim_y=-800)
# Overall height
dimension_linear(x1=0, y1=0, x2=0, y2=8000, dim_x=-800, dim_y=4000)
# Room widths
dimension_linear(x1=0, y1=8000, x2=5000, y2=8000, dim_x=2500, dim_y=8500)
dimension_linear(x1=5000, y1=8000, x2=12000, y2=8000, dim_x=8500, dim_y=8500)
```
## Add Room Labels
```
layer_set_current("TEXT")
entity_create_text(text="LIVING ROOM", x=2500, y=4000, height=300)
entity_create_mtext(text="12.0 m²", x=2500, y=3500, width=2000, height=200)
entity_create_text(text="BEDROOM", x=8500, y=6000, height=300)
entity_create_mtext(text="28.0 m²", x=8500, y=5500, width=2000, height=200)
entity_create_text(text="KITCHEN", x=8500, y=2000, height=300)
entity_create_mtext(text="28.0 m²", x=8500, y=1500, width=2000, height=200)
```
## Verify
```
analysis_entity_stats()
analysis_layer_stats()
validation_check(["empty_layers", "zero_length"])
drawing_save("C:/drawings/apartment.dxf")
```
@@ -0,0 +1,105 @@
# Example: Flange with Bolt Pattern
Create a circular flange plate with bolt holes using polar array.
## Setup
```
drawing_new()
template_apply_layers("mechanical")
# Creates: OUTLINE, CENTERLINE, HIDDEN, DIMENSIONS, NOTES, SECTION, DETAIL
```
## Draw Flange Outline
```
layer_set_current("OUTLINE")
# Outer flange circle (diameter 200mm)
entity_create_circle(cx=0, cy=0, radius=100)
# Returns: {handle: "F1", ...}
# Inner bore (diameter 50mm)
entity_create_circle(cx=0, cy=0, radius=25)
# Returns: {handle: "F2", ...}
```
## Add Centerlines
```
layer_set_current("CENTERLINE")
# Horizontal centerline
entity_create_line(x1=-120, y1=0, x2=120, y2=0, linetype="CENTER")
# Vertical centerline
entity_create_line(x1=0, y1=-120, x2=0, y2=120, linetype="CENTER")
```
## Create Bolt Hole Pattern
```
layer_set_current("OUTLINE")
# First bolt hole on bolt circle (PCD = 150mm diameter, so radius = 75mm)
entity_create_circle(cx=75, cy=0, radius=6)
# Returns: {handle: "B1", ...}
# Create polar array: 6 holes evenly spaced
entity_array_polar(handle="B1", center_x=0, center_y=0, count=6, angle=360)
# Returns: list of 5 new handles (original + 5 copies = 6 total)
```
## Add Dimensions
```
layer_set_current("DIMENSIONS")
# Outer diameter
dimension_diameter(x1=-100, y1=0, x2=100, y2=0)
# Inner bore diameter
dimension_diameter(x1=-25, y1=0, x2=25, y2=0)
# Bolt circle diameter
dimension_radius(center_x=0, center_y=0, radius=75, angle=45)
# Bolt hole diameter
dimension_diameter(x1=69, y1=0, x2=81, y2=0)
```
## Add Notes
```
layer_set_current("NOTES")
entity_create_mtext(
text="FLANGE PLATE\P6x M12 HOLES ON PCD 150\PMATERIAL: SS304",
x=-120, y=-140,
width=240, height=5
)
```
## Create Block from Bolt Hole
```
# Select all bolt hole entities and create a reusable block
# (Get handles from the array result)
block_create_from_entities(
name="BOLT_PATTERN_6x150",
handles=["B1", ...], # all bolt hole handles
base_x=0, base_y=0
)
```
## Verify
```
analysis_entity_stats()
# Expected: circles, lines, dimensions, mtext
analysis_bounding_box()
# Expected: approximately -120 to 120 in both axes
drawing_save("C:/drawings/flange.dxf")
```
@@ -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")
```
@@ -0,0 +1,79 @@
"""Check AutoCAD MCP Pro setup and dependencies."""
import importlib
import os
import sys
def check(name: str, condition: bool, fix: str = ""):
status = "OK" if condition else "MISSING"
symbol = "[+]" if condition else "[-]"
line = f" {symbol} {name}: {status}"
if not condition and fix:
line += f" -> {fix}"
print(line)
return condition
def main():
print("AutoCAD MCP Pro — Setup Check\n")
ok_count = 0
total = 0
print("Python:")
total += 1
v = sys.version_info
ok_count += check(
f"Python {v.major}.{v.minor}.{v.micro}",
v >= (3, 11),
"Requires Python 3.11+",
)
print("\nRequired packages:")
for pkg, install in [
("fastmcp", "pip install fastmcp"),
("ezdxf", "pip install ezdxf"),
("pydantic", "pip install pydantic"),
]:
total += 1
try:
importlib.import_module(pkg)
ok_count += check(pkg, True)
except ImportError:
ok_count += check(pkg, False, install)
print("\nOptional packages:")
for pkg, install, purpose in [
("win32com", "pip install pywin32", "COM backend"),
("PIL", "pip install Pillow", "Screenshots (COM)"),
("matplotlib", "pip install matplotlib", "PDF export + screenshots (ezdxf)"),
]:
total += 1
try:
importlib.import_module(pkg)
ok_count += check(f"{pkg} ({purpose})", True)
except ImportError:
ok_count += check(f"{pkg} ({purpose})", False, install)
print("\nEnvironment variables:")
for var, default in [
("AUTOCAD_MCP_BACKEND", "auto"),
("ALLOWED_PATHS", "(empty = all paths allowed)"),
("MAX_UNDO_STACK", "50"),
("LOG_LEVEL", "INFO"),
("DANGEROUS_COMMANDS_ENABLED", "false"),
]:
val = os.environ.get(var, "")
total += 1
ok_count += check(var, True, "")
if val:
print(f" Current value: {val}")
else:
print(f" Default: {default}")
print(f"\nResult: {ok_count}/{total} checks passed")
return 0 if ok_count >= 4 else 1
if __name__ == "__main__":
sys.exit(main())
@@ -0,0 +1,91 @@
"""Validate drawing quality — run after creating/editing a drawing.
Usage: python scripts/validate_drawing.py [drawing_path]
This script checks for common drawing issues:
- Empty layers (layers with no entities)
- Entities on layer "0" (should use named layers)
- Entity count summary
"""
import json
import sys
def validate_stats(stats: dict) -> list[str]:
"""Validate entity statistics. Pass the result of analysis_entity_stats()."""
issues = []
if stats.get("total", 0) == 0:
issues.append("WARNING: Drawing has no entities")
by_layer = stats.get("by_layer", {})
if "0" in by_layer and by_layer["0"] > 0:
issues.append(
f"INFO: {by_layer['0']} entities on default layer '0' "
"(consider moving to named layers)"
)
return issues
def validate_layers(layers: list[dict]) -> list[str]:
"""Validate layer configuration. Pass the result of layer_list()."""
issues = []
for layer in layers:
name = layer.get("name", "")
if name == "0":
continue
if layer.get("color", 7) == 7 and name != "0":
issues.append(
f"INFO: Layer '{name}' uses default color (white/7). "
"Consider assigning a distinct color."
)
return issues
def main():
print("Drawing Validation Tool")
print("=" * 40)
print()
print("This tool validates output from MCP analysis tools.")
print("Pipe JSON from analysis_entity_stats() or layer_list().")
print()
print("Usage with MCP:")
print(" 1. Call analysis_entity_stats() → copy JSON output")
print(" 2. Call layer_list() → copy JSON output")
print(" 3. Review results for issues")
print()
print("Checks performed:")
print(" - Empty drawing detection")
print(" - Entities on default layer '0'")
print(" - Layers with default color")
print()
if not sys.stdin.isatty():
try:
data = json.load(sys.stdin)
if "total" in data:
issues = validate_stats(data)
elif isinstance(data, list):
issues = validate_layers(data)
else:
issues = ["ERROR: Unrecognized input format"]
if issues:
for issue in issues:
print(f" {issue}")
else:
print(" OK — No issues found")
except json.JSONDecodeError:
print(" ERROR: Invalid JSON input")
else:
print("No stdin input. Run interactively or pipe JSON data.")
return 0
if __name__ == "__main__":
sys.exit(main())