Skip to main content
Glama
U-C4N
by U-C4N

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
LOG_LEVELNoStandard Python logging level.INFO
ALLOWED_PATHSNoComma-separated absolute paths the server may read/write.
MAX_DXF_BYTESNoReject DXF files larger than this on drawing_open. 0 to disable.52428800
MAX_LIST_LIMITNoHard cap for entity_list and analysis_select_* responses.5000
MAX_UNDO_STACKNoMaximum number of in-flight transaction snapshots.5
MCP_AUTH_TOKENNoRequired when ALLOW_REMOTE_HTTP=true. Bearer token for HTTP clients.
COM_CALL_TIMEOUTNoPer-call timeout for COM operations in seconds.60
ALLOW_REMOTE_HTTPNoPermit HTTP transport on non-loopback hosts.false
AUTOCAD_MCP_BACKENDNoBackend selection (auto, com, ezdxf).auto
DANGEROUS_COMMANDS_ENABLEDNoDisable command and AutoLISP sanitization. Loud warning at startup.false

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": true
}
logging
{}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}
extensions
{
  "io.modelcontextprotocol/ui": {}
}
experimental
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
drawing_infoA

Get comprehensive metadata for the current drawing.

Returns: name, path, entity_count, layer_count, block_count, extents (min/max), units, version, backend name.

drawing_newA

Create a new drawing, optionally from a template.

A bundled name resolves to templates/<name>.dxf headlessly and templates/<name>.dwt on the live engine (falling back to the DXF with source: "bundled_dxf" when no .dwt twin is committed); a path is used as given. The result carries template: {name|path, path, source}.

On the live engine only a genuine .dwt reaches Documents.Add — measured on AutoCAD 2026, Add(<file.dxf>) silently returns the default drawing — so a .dxf template (bundled or a path) is first converted through AutoCAD into a cached .dwt and template.dwt names it (template.dwt_cached says whether the conversion was reused). The drawing then really carries the template's layers, tabs and page setup.

Refused before anything is replaced: a bare name that is not in the catalogue (the message lists the five), a template path that does not exist, and a path outside the allowed directories. With bootstrap=True (default) the standard engineering linetypes and layers are ensured afterwards — idempotent on a template that already has them.

drawing_openA

Open an existing DXF drawing file (DWG too, on the live COM backend).

T0.2: a .dwg path is refused up front when the active backend has no dwg capability. ezdxf sniffs content rather than extensions, so it would parse a mislabelled DXF-in-a-.dwg and this tool would answer with a document that does not exist in that format.

drawing_saveB

Save the current drawing. Optionally specify a new path.

drawing_save_asA

Save current drawing to a new path/format (DWG, DXF, or DWT template).

The on-disk format is derived from the file extension so the bytes always match the name (N2) — e.g. 'part.dxf' writes DXF, not DWG. format overrides only when the path has no recognised extension.

drawing_export_dxfA

Export the current drawing as a DXF file.

drawing_export_pdfA

Export the current drawing (or a paper-space layout) to PDF.

drawing_purgeA

Purge all unused objects (layers, blocks, linetypes, styles) from the drawing.

drawing_auditA

Audit the drawing: repair every fixable structural problem, and report it.

This mutates the drawing. fixes lists repairs that have ALREADY been applied, so save afterwards to keep them; errors lists problems that could not be repaired. On the live COM backend AutoCAD applies repairs but hands back no counts, so they arrive as null with detail: "unavailable" rather than as zero.

drawing_closeA

Close the active document. If save is True (default), the drawing is saved to its current path before closing; an untitled document is closed and warning says its changes were discarded (headless) or the call is refused (live, where the alternative is a modal Save dialog). The active-document case of document_close; after the last document is closed, call drawing_new or drawing_open before any other tool.

drawing_undoA

Undo the last drawing operation.

On the live COM backend this is AutoCAD's own undo. The headless backend has no journal, so a step is a full DXF snapshot and history is off by default — set EZDXF_UNDO_DEPTH to the number of steps you want. Measured cost of switching it on: 37x on entity creation (0.18 -> 6.65 ms per call). For a single checkpoint around a risky sequence, transaction_begin / transaction_rollback is far cheaper.

Drawing something after an undo discards the redo branch, as in AutoCAD.

drawing_redoA

Reapply the operation you just undid.

Same history as drawing_undo, so the headless backend needs EZDXF_UNDO_DEPTH set. Anything drawn after an undo discards the redo branch — otherwise redo would restore a state that never existed, with geometry you had removed reappearing beside geometry you drew afterwards.

entity_create_lineA

Create a line from (x1,y1) to (x2,y2). Returns entity info with handle.

entity_create_circleA

Create a circle at (cx, cy) with given radius.

entity_create_arcA

Create a circular arc. Angles are in degrees, measured counter-clockwise from the positive X axis.

entity_create_polylineA

Create a lightweight 2D polyline through the given points.

Example: points=[[0,0],[100,0],[100,100],[0,100]], closed=true → rectangle

entity_create_rectangleA

Create a closed rectangular polyline between two corner points.

Convenience wrapper around entity_create_polyline.

entity_create_textA

Create a single-line text entity (DTEXT/TEXT).

entity_create_mtextA

Create a multi-line text entity (MTEXT) with word-wrap at the specified width.

entity_create_tableB

Create a native COM table or an explicitly-labelled ezdxf composite table.

leader_create_mleaderC

Create a native COM MLeader or an explicitly-labelled ezdxf composite.

entity_create_hatchB

Create a hatch fill pattern inside a closed boundary polygon.

entity_create_splineA

Create a NURBS spline curve passing through the specified fit points.

entity_create_ellipseA

Create an ellipse. major_x/major_y define the major axis vector from the center.

entity_create_pointB

Create a point marker entity at (x, y).

entity_create_block_refA

Insert a block reference (instance of an existing block definition).

Refused before any write, on both engines: a name that is not a block definition in this drawing (block 'X' is not defined — check block_list), a layout block (*Model_Space / *Paper_Space, a reference cycle) and a non-string name. The same gate as block_insert; this tool is the no-attributes form.

hatch_set_gradientA

Fill a hatch with a gradient instead of a pattern.

hatch_editA

Edit an existing hatch in place.

Omitted parameters are left alone — a partial edit that resets the rest is data loss. changed reports which attributes actually moved, so re-setting a value to what it already was comes back as an empty list rather than a false positive.

hatch_add_boundaryA

Add one boundary path built from typed edges - an island inside the hatch.

Typed edges exist because a boundary that only accepts vertex lists silently straightens every curve it is given. Every edge is validated before any is written, so a malformed list refuses instead of leaving a half-built path. Both engines: headlessly the edges become an edge path; on a live seat each becomes a temporary LINE, true ARC or ELLIPSE appended as an inner loop and then deleted (a chain of lines becomes one polyline). A loop that does not close is refused by AutoCAD and nothing is added.

entity_create_wipeoutA

Create a WIPEOUT that hides drawing content behind its outline.

Refuses fewer than three points: a zero-area mask hides nothing while reporting success.

entity_create_revcloudA

Draw a revision cloud: a polyline whose every segment carries an arc.

A segment_length longer than the shortest edge is refused — the result would carry no arcs at all and would be a plain polyline reported as a cloud.

dimension_linearB

Create a linear dimension, optionally toleranced (ISO 129 or ISO 286 fit).

dimension_alignedA

Create an aligned dimension that measures the true distance between two points.

dimension_angularA

Create an angular dimension measuring the angle between two lines from a vertex.

dimension_radiusA

Create a radius dimension for a circle or arc, optionally toleranced.

dimension_diameterA

Create a diameter dimension for a circle, optionally toleranced (e.g. ⌀20 H7).

entity_moveA

Move an entity by the specified displacement vector (dx, dy, dz).

entity_copyA

Copy an entity and move the copy by (dx, dy, dz). Returns info of the new copy.

entity_rotateA

Rotate an entity around a base point by the specified angle.

entity_scaleA

Scale an entity uniformly from a base point.

entity_mirrorA

Mirror an entity across a line defined by two points. Returns the mirrored copy.

entity_offsetB

Create a parallel copy of a line, circle, or polyline at the given distance.

entity_trimA

Trim target against cutter, keeping the segment containing (keep_x, keep_y).

V1 supports LINE+LINE only. Cutter is treated as an infinite ray (AutoCAD's default 'implied extend' trim mode). Raises if the lines are parallel.

entity_extendA

Extend target to meet boundary. If end_x/end_y is None, the target endpoint nearest the boundary is auto-selected.

V1 supports LINE+LINE only. Raises if the lines are parallel.

entity_filletA

Round a corner with a tangent arc. Returns info on the new ARC entity (or the first source line for radius=0). V1 supports LINE+LINE only.

entity_chamferA

Bevel a corner with a chamfer line. Returns info on the new chamfer LINE. V1 supports LINE+LINE only.

entity_deleteA

Permanently delete an entity by its handle.

entity_array_rectangularA

Create a rectangular array of copies. Returns info of all created copies.

rows x cols is unbounded, so this is a result-heavy tool despite being a create: a 40x40 grid hands back 1600 full records. fields=["handle"] is usually all a caller needs from it.

entity_array_polarA

Create a polar (circular) array of copies around a center point.

count is unbounded, so the same result-shaping applies as for the rectangular array: fields=["handle"] when the geometry is already known.

entity_set_propertiesA

Change one or more properties of an entity (layer, color, linetype, lineweight, visibility).

entity_edit_textA

Edit an existing text label in place — change its content, height, or rotation.

Use this to rename/relabel without deleting and recreating (which would lose the handle). Works on both TEXT and MTEXT.

text_set_backgroundA

Mask what is behind an MTEXT so it stays readable over hatch or geometry.

MTEXT only: TEXT has no background-fill attribute, so setting one on it would report success and change nothing.

text_find_replaceA

Replace text in TEXT, MTEXT and block attributes (ATTRIB and ATTDEF).

searched_types is on the response because "no matches" and "that type was never searched" are different answers. Block definitions are included, so the next insert does not reintroduce the old text. DIMENSION text is out of scope: its text field holds the <> override placeholder rather than the measurement, so editing it would break the association. A multi-line attribute is matched and rewritten as the whole value (Line1\PLine2), the same value block_get_attributes reports and block_explode bursts.

entity_edit_geometryA

Edit the defining geometry of an existing entity in place (no delete/recreate).

CIRCLE: cx/cy/radius · LINE: x1/y1/x2/y2 · ARC: cx/cy/radius/start_angle/end_angle. Any argument left out is unchanged; the handle is preserved.

selection_windowA

AutoCAD's ssget window/crossing selection.

Corners may be given in any order. Selection is by drawn position, so an entity in a mirrored frame is found where entity_get reports it. A zero-area box is refused rather than answered with an empty list.

selection_polygonA

Window or crossing selection against a polygon rather than a rectangle.

selection_filterA

AutoCAD's QSELECT: filter the drawing by properties.

Named parameters rather than a query string, deliberately — a mistyped attribute name in a query language comes back as an empty result, which is indistinguishable from "no matches". filtered_by reports which filters actually ran.

entity_getA

Get all properties of a specific entity by its handle.

entity_listA

List entities in the drawing with optional type and layer filters.

Returns handle, type, layer, color, and type-specific properties. Use handles with entity_get, entity_move, entity_delete, etc.

This is the most expensive result on the server — the full record runs ~250 characters per entity, and properties.bounding_box alone is about a third of it. When all you need is handles, say so::

entity_list(layer_filter="GEOMETRY", fields=["handle", "type"], compact=True)

Paging honesty: a plain list has nowhere to say that more entities followed the page, so compact=True is the only mode that reports total, truncated and next_offset — all measured against the same filters.

entity_delete_manyA

Delete multiple entities in one call. Returns count of deleted entities.

selection_getA

Read the entities the user pre-selected in the AutoCAD viewport (COM backend only).

Returns the implied "pickfirst" selection — the entities highlighted with grips before invoking the AI — so work can be scoped to exactly those entities instead of the whole drawing. Typical use::

sel = selection_get()
dimension_auto(sel["handles"], style="chain")

Result keys: ok — True on the COM backend (even for an empty selection) count — number of selected entities handles — list of entity handles (hex strings) to act on entities — full per-entity info (type, layer, color, ...) pickfirst — state of the PICKFIRST sysvar (None if unknown) message — guidance when nothing is selected

On the ezdxf headless backend there is no viewport, so this returns ok=False with an empty handles list.

fields / compact shape the "entities" collection — this tool already returns an object, so the columnar envelope lands under that key rather than replacing the result. handles is unaffected, so a caller that only wants handles can pass fields=["handle"] and still read handles directly.

entity_get_xdataC

Extended entity data as {app: [values]}. An app with no XDATA is simply absent.

entity_set_xdataA

Replace the named app's XDATA on one entity; an empty list removes it.

Limits are AutoCAD's and are enforced before writing: 255 characters per string and 16 KB per entity.

layer_listA

List all layers with their properties (color, linetype, frozen, locked, visibility).

Never truncated — a drawing's whole layer table is returned — so a compact envelope here always reports truncated=false.

layer_createB

Create a new layer with specified properties.

layer_deleteA

Delete a layer. The layer must have no entities. Layer '0' cannot be deleted.

layer_set_currentA

Set the active/current layer for new entities.

layer_modifyA

Modify an existing layer's color, linetype, and/or lineweight.

layer_freezeA

Freeze a layer (makes it invisible and unselectable, faster regeneration).

layer_thawA

Thaw a frozen layer, making it visible and selectable again.

layer_lockA

Lock a layer (entities visible but cannot be selected or modified).

layer_unlockA

Unlock a layer to allow entity selection and modification.

layer_hideA

Turn off a layer (entities invisible but still processed in regeneration).

layer_showA

Turn on a layer that was previously turned off.

layer_isolateA

Hide all layers except the specified one (layer isolation).

linetype_listA

Return the names of all linetypes currently loaded in the active drawing.

linetype_loadA

Load a single linetype safely.

Use this instead of system_run_command('_-LINETYPE _LOAD ...') — that raw form deadlocks on the FILEDIA file-picker dialog and on the -LINETYPE option-menu prompt (measured on AutoCAD 2026: it loads nothing either way). This tool loads through the ActiveX Linetypes.Load member, picks the right .lin file from MEASUREMENT, and verifies the linetype actually loaded. Refuses a name that is not a valid symbol name, a file outside the allowed paths, and reports a name the file does not carry or a file AutoCAD cannot find as an error naming both.

block_listA

List all block definitions in the drawing (name, origin, attribute count, entity count).

Never truncated — the whole block table is returned — so a compact envelope here always reports truncated=false.

block_insertA

Insert a block and optionally set attribute values.

Refused before any write, on both engines: an undefined or layout block name, and an attribute value that is not text — a string is written as is (one line), an int or finite float as its plain digits (101 → "101"), while null, booleans, lists and objects are refused naming the tag (they used to be written as their Python repr). Values for tags the block does not define are ignored.

block_explodeA

Explode a block reference into its component entities, keeping its attribute text (the Express Tools BURST rule, on both engines).

Every attached ATTRIB becomes a TEXT with the same value, placement, height, rotation and layer (an invisible attribute becomes an invisible TEXT; a multi-line attribute becomes an MTEXT carrying every line), and a constant attribute (which has no ATTRIB) becomes a TEXT of its value too; AutoCAD's plain EXPLODE would keep only the tag-name placeholders and drop the values. Everything lands in the layout that owns the reference (model space or its paper-space sheet), whichever tab is current. Returns inserted_handles (the geometry), attribute_texts (one TEXT or MTEXT handle per attribute), exploded_handle and backend. Refused, with nothing written: a handle that is not a block reference, a reference nested inside a block definition (explode the outer reference instead), an external reference (bind it first), a MINSERT grid, and -- headless only, capability explode_opaque_members -- a block holding a member ezdxf cannot transform (an OLE2FRAME logo, a VIEWPORT, a proxy entity without proxy graphics), named by member; the live engine hands those to AutoCAD. Not undoable except through drawing_undo / a transaction.

block_get_attributesA

Get all attribute values from a block reference as {TAG: value} dict.

A multi-line attribute reports its whole content with \P between the lines (AutoCAD's TextString), on both engines.

block_set_attributesA

Update attribute values in a block reference.

Same value rule as block_insert: strings and numbers are written, null / booleans / lists / objects are refused naming the tag before anything changes. updated_tags lists the tags that exist on the reference and were written; unknown tags are ignored.

A multi-line attribute takes Line1\PLine2 and keeps every line; the value written is the one block_get_attributes reads back and block_explode bursts, on both engines.

block_create_from_entitiesA

Create a new block definition from existing entities in the drawing.

Works on both engines. The originals stay in model space — this defines a reusable block from them rather than consuming them the way AutoCAD's BLOCK command does; use block_insert to place copies, and delete the originals yourself if you want the command's behaviour.

Handles that do not resolve are listed in skipped rather than silently dropped, and a call where none resolve fails instead of leaving an empty definition behind.

block_defineA

Create a block definition with attribute definitions from typed specs.

The whole request is validated before anything is written: one malformed entry refuses the call and leaves no definition behind. Refusals: a malformed primitive or ATTDEF (names entities[i]/attdefs[i] and the key), a non-finite base point (names base_x/base_y), a name clash without overwrite, an anonymous * name, and a primitive layer that is not in the drawing's layer table (names the missing layers) unless create_layers=true, which creates them and lists them in layers_created. overwrite=true replaces the contents of an existing block so its INSERTs keep pointing at the name and show the new geometry; replaced reports it. Geometry inside the block is ByBlock so the INSERT's layer supplies colour and lineweight. Insert with block_insert(attributes={TAG: value}).

block_find_referencesA

Find all insert references to a specific block definition.

Bounded by the backend's own default entity_list page (200 INSERTs scanned), which is a pre-existing limit, not a new one: the compact envelope's total counts the references found within that scan.

boundary_traceA

AutoCAD's BOUNDARY/BPOLY: create a closed polyline around a seed point.

Returns the nearest enclosing loop, so a seed inside an island gives the island rather than the outer region. Straight edges are split where they cross, so a line drawn across a shape divides it the way it looks like it should. A seed with no enclosing loop is refused, and the error names the gap when the edges nearly close.

boundary_from_entitiesA

Chain the given entities into one closed polyline.

The handles may arrive in any order — putting them in chain order is the tool's job. A chain that does not close is refused, and the error names the coordinates of the gap.

analysis_list_propertiesA

AutoCAD's LIST: the full DXF attribute set for one handle.

dxf_attributes is the raw attribute set entity_get deliberately does not carry. Coordinates in it are WCS, like everywhere else in this server, and extrusion is reported so the entity's own frame is still visible.

analysis_entity_statsA

Analyze the drawing and return entity counts grouped by type and by layer.

Returns: total_entities, by_type (sorted by count), by_layer (sorted by count). This is unique to AutoCAD MCP Pro – no other MCP server provides this!

analysis_find_in_regionA

Find all entities within a rectangular region (crossing selection).

Uncapped: a window over a busy drawing returns every hit. Project with fields and/or compact before widening the window.

analysis_measure_distanceA

Measure the Euclidean distance between two points.

analysis_measure_areaA

Area and perimeter of a polygon you supply the vertices for.

This measures the numbers in the call, NOT the drawing. To measure something that exists, use analysis_measure_entity(handle) — it reads the real geometry, including curvature this tool can only see if you pass it.

Straight-edged polygons are exact. Pass a third bulge element per vertex for arc edges; omitting it on curved geometry under-reports (28% on a semicircular edge), which is why assumes says what was taken on faith.

analysis_measure_entityA

Measure something already in the drawing, by handle.

Reads the real geometry, so polyline bulges (arc edges) are included — reading vertices back and shoelacing them yourself loses 28% of the area on a semicircular edge, silently.

Measurable: LWPOLYLINE, 2D POLYLINE, CIRCLE, ELLIPSE, SPLINE, HATCH, SOLID, TRACE, 3DFACE. REGION and 3DSOLID need the live COM backend (their area is in ACIS data ezdxf cannot evaluate) and refuse with capability: "measure_area_acis". LINE/TEXT/INSERT bound no area on any engine and are a plain error, not a capability gap.

The payload states its own accuracy: exact is false when the shape had to be flattened (then flatten_tolerance says how finely), assumed_closed is true when an open boundary was closed the way AutoCAD's AREA does, and self_intersecting warns when the shoelace cancelled crossed lobes — a bowtie measures 0.0 and that number is worse than useless unflagged.

analysis_bounding_boxA

Get the bounding box (extents) of all entities in the drawing.

analysis_select_by_layerA

Get all entities on a specific layer. Returns entity list with handles.

Capped at MAX_LIST_LIMIT (default 5000). The plain list cannot say it was capped — the warning goes to the log stream, which most clients never show the model — so use compact=True when the count matters: its total is the layer's real population and truncated states whether the cap fired.

analysis_select_by_typeA

Get all entities of a specific type. Returns entity list with handles.

Capped at MAX_LIST_LIMIT (default 5000); as with analysis_select_by_layer, compact=True is the only shape that reports total and truncated.

analysis_layer_statsA

Return detailed statistics for each layer: entity count, types present.

cad_batchA

Execute an ordered list of tool calls in ONE round trip.

N calls collapse into one request/response pair, and bind lets a later step reference an earlier step's result so handles never have to be echoed back through the model.

steps=[
  {"tool": "entity_create_line",  "args": {...}, "bind": "edge"},
  {"tool": "point_from_snap",     "args": {"handle": "$edge", "snap": "mid"},
                                  "bind": "mid"},
  {"tool": "entity_create_circle","args": {"cx": "$mid.x", "cy": "$mid.y",
                                           "radius": 4}},
]

Successful steps report only their handle; pass verbose=True for the full result. Anything without a handle is returned whole.

VALIDATION runs first, always: an unknown tool, a schema-invalid argument or a reference no earlier step binds refuses the whole batch before anything executes. on_error governs run-time failures only. dry_run=True returns that validation report and executes nothing.

ERRORS are typed, never text: each failed step carries error.kind - one of unsupported (with the backend capability), invalid_args, refused, failed, unknown_tool, unresolved_ref, denied, malformed_step.

ATOMICITY is reported, not assumed. Read the atomicity block: on the headless backend rollback restores a full document snapshot; on live AutoCAD it sends an UNDO whose landing AutoCAD never confirms. The default on_error="stop" claims nothing and is exact on both.

NOT CALLABLE from a batch: the raw command/LISP escape hatches, and cad_batch itself. Call those directly.

For a few hundred entities of the same kind, entity_batch_create is denser still (no per-step tool name) - and it can be one step of a cad_batch.

entity_batch_createA

Create multiple entities in a single call for better performance.

Each entity dict must have a 'type' key and the parameters for that type. Example: [{"type": "line", "x1": 0, "y1": 0, "x2": 100, "y2": 0}, {"type": "circle", "cx": 50, "cy": 50, "radius": 25}]

Denser than cad_batch for many entities of the same kind (no per-step tool name), and usable as one step of a cad_batch. Use cad_batch when the calls differ, must be ordered, or must feed each other.

entity_batch_modifyA

Apply multiple modifications in a single call.

Example: [{"handle": "1A", "action": "move", "dx": 10, "dy": 20}, {"handle": "2B", "action": "delete"}]

Covers move/rotate/scale/delete/set_properties only. For anything else, for ordering, or to feed one step's result into the next, use cad_batch.

template_apply_layersA

Apply a standard layer set from a predefined template.

Available templates: architectural, mechanical, electrical, piping. Creates all layers defined in the template with standard colors and lineweights.

template_listA

List all available layer templates and their contents.

validation_checkA

Run quality checks on the current drawing.

Available checks:

  • empty_layers: Find layers with no entities

  • zero_length: Find zero-length lines

  • duplicate_entities: Find entities at the same position

view_zoom_extentsA

Zoom to show all entities in the drawing (fit drawing in viewport).

view_zoom_windowA

Zoom to display the specified rectangular window region.

view_screenshotA

Capture a screenshot of the current drawing view.

COM backend: captures live AutoCAD window at current view. ezdxf backend: renders via matplotlib to PNG.

With overlay_handles, each entity is labelled with its handle at its own centre — every modify tool takes a handle, and without the labels there is nothing connecting "the circle at the top-left" to a hex string you can act on. Crowded drawings are capped and the image says how many of how many were labelled. Live AutoCAD captures its own window, so there is no render to label there; it refuses with capability: "handle_overlay".

Returns an Image content block with the PNG data.

view_zoom_and_screenshotA

Zoom to extents (or window if coordinates given), then capture a screenshot.

The most useful tool for visually inspecting drawing state.

transaction_beginA

Begin a transaction (undo mark).

COM backend: Sets AutoCAD undo mark. All subsequent operations can be rolled back to this point with transaction_rollback.

ezdxf backend: Saves a DXF snapshot. Rollback restores the full document state to this point.

Always pair with transaction_commit or transaction_rollback.

transaction_commitA

Commit the current transaction.

COM: Ends the undo mark (changes are permanent but still undoable via drawing_undo). ezdxf: Discards the rollback snapshot (changes are kept).

transaction_rollbackA

Rollback the current transaction to the point of transaction_begin.

COM: Undoes all operations back to the UNDO Mark transaction_begin set; refused (ok: false) when no transaction is active. ezdxf: Restores the document from the saved DXF snapshot.

WARNING: This is destructive – all changes since transaction_begin are lost.

system_statusA

Get full status of the AutoCAD MCP Pro server and backend connection.

Returns backend name, connection status, capabilities, document info.

system_capabilitiesA

Return machine-readable support modes for the active backend.

system_get_variableB

Get an AutoCAD system variable value.

system_set_variableA

Set an AutoCAD system variable (e.g. DIMSCALE, LTSCALE, MEASUREMENT).

Refusals, before anything is written: a value outside the catalogued range or enum of a known variable, or a write to a read-only variable (DIMSTYLE, CANNOSCALEVALUE, DWGNAME, …), is refused with the catalogue's message — system_variable_describe(name) shows the range. A variable the catalogue does not know is passed through unchanged. The headless engine additionally refuses registry-saved variables (capability: registry_sysvar) because a file has nowhere to keep them, and names that ezdxf has no header slot for (a ValueError naming the variable).

drawing_settingsA

Read or change common AutoCAD drawing settings by friendly name.

A convenience facade over the system variables (INSUNITS, LUPREC, LTSCALE, DIMSCALE, DIMTXT, DIMASZ, DIMDEC, DIMDSEP, DIMZIN, TEXTSIZE, OSMODE, LIMMIN/ LIMMAX, GRIDMODE/GRIDUNIT, SNAPMODE/SNAPUNIT, ORTHOMODE, AUTOSNAP/POLARANG, PSLTSCALE, CANNOSCALE, LUNITS, AUNITS, DIMSTYLE, TEXTSTYLE) so the user can say "set units to mm, limits to A3 and the grid on" without memorising sysvar names. Call with no argument for a full snapshot; a write returns applied, changed ({key: [old, new]} — only what moved) and errors.

dim_text_height / dim_arrow_size / dim_decimals / decimal_separator / zero_suppression shape the dimension — text_size is TEXTSIZE, the height of a standalone TEXT entity, and does not touch dimensions.

Refusals, per key, nothing else rolled back: an unknown key; a value outside its range (grid/snap spacing > 0, polar_angle 0–360, precision 0–8, …); a malformed limits or annotation_scale; osmode / polar / polar_angle on the headless engine (capability: registry_sysvar — AutoCAD keeps them in the registry, a file cannot, and a headless snapshot reports them as None); dimstyle / textstyle when the backend has no styles contract. On the live engine annotation_scale must name a scale in the drawing's scale list (SCALELISTEDIT) and AutoCAD refuses the write on a paper-space layout with no active viewport; the headless engine adds the scale, seeding AutoCAD's default list first when the drawing has none, and refuses it on an R12 file (no OBJECTS section, so the value would vanish at save — save as R2000 or newer first; limits/grid/ortho survive). Headlessly, grid/snap are stored on the active VPORT and the annotation scale in the variable dictionary — the places AutoCAD reads them from.

system_run_commandA

Execute an AutoCAD command string directly (COM backend only).

Append \n for Enter. Example: '_LINE 0,0 100,0 \n'.

IMPORTANT: commands that finish at an option menu (e.g. -LINETYPE, -LAYER, -STYLE return to '[?/Create/Load/Set]:' after their action) need an EXTRA blank line or 'X\n' to exit, otherwise AutoCAD stays at a prompt and the next COM call will deadlock. Example: '-LINETYPE _LOAD CENTER acad.lin\n\n'.

A verb denylist refuses obviously destructive commands, but it is a guardrail against issuing ERASE ALL by accident, NOT a security boundary — AutoCAD accepts hundreds of commands and any loaded ARX/LISP adds more. Prefer the typed tools (entity_delete, drawing_save_as, block_insert, drawing_purge): they validate their arguments, which a free-text command string cannot.

system_run_lispA

Execute an AutoLISP expression (COM backend only).

Example: '(setvar "DIMSCALE" 1.0)'

A symbol denylist refuses the known code-execution and file-I/O channels; text inside double quotes is treated as data, so drawing notes are not mistaken for code. It is a guardrail, NOT a security boundary — AutoLISP has more write channels than any denylist enumerates. Prefer the typed tools.

system_aboutB

Get detailed information about AutoCAD MCP Pro capabilities and available tools.

gear_draw_helical_front_viewA

Deterministic helical gear front view: full involute outline (40 pts/flank), pitch/base/outer/root circles, helix symbol, optional bore + keyway.

Returns a handle bundle plus 'metadata' for downstream gear_draw_section_aa.

gear_draw_spur_front_viewB

Deterministic spur gear front view (no helix symbol).

gear_draw_section_aaA

Deterministic side cross-section of a gear created by gear_draw_*_front_view. Includes top/bottom/left/right boundaries, bore lines, keyway notch, ANSI31 hatch.

keyway_draw_keyed_boreA

Bore + DIN 6885 keyway in front view. Auto-sizes keyway from bore if width/depth omitted.

keyway_draw_sectionC

Side cross-section view of a keyed bore.

titleblock_apply_iso_a3A

ISO 7200 / A3 (420x297 mm) title block. Title text is used verbatim.

Pass layout to put the sheet on a paper-space layout, which is where a title block belongs — the border frames the printed sheet, not the model. Your current space is restored afterwards, so asking for a border does not move you onto the sheet.

drawing_finalizeA

Premium completion gate: runs BOTH the 8-step validator AND the premium critique focuses (iso128, layer_color, dim_overlap, untrimmed_corner, duplicate_entities, construction_left, gdt, plus the P&ID focuses pid_dangling_line, pid_duplicate_tag, pid_incompatible_connection, pid_untagged_instrument, pid_illegal_tag, pid_unconnected_equipment — silent on a sheet with no P&ID symbols, plus the mechanical focuses mech_missing_centreline, mech_unhatched_section, mech_view_misaligned, mech_duplicate_dimension, mech_thread_unrepresented, mech_bom_balloon_mismatch — silent on a sheet with no mechanical part, plus the architectural focuses arch_room_unlabelled, arch_wall_gap, arch_opening_clash — silent on a sheet with no ACADMCP_ARCH record, plus the topology focuses topo_dangling_endpoint, topo_near_miss, topo_interior_crossing — on network layers no P&ID or architectural focus reads, silent on every sheet this server draws), then saves to disk, exports a screenshot, and returns the DWG path.

Raises ToolError if any validator 'error' finding is present, or if critique reports an 'error' (or, with strict_critique=True, any critique issue). Critique warnings are surfaced under payload['critique'] without failing the gate by default.

drawing_deliverA

Create a hashed, validated delivery bundle and verify DXF save/reopen parity.

The result status is success, failed_validation or failed_export. Failure intentionally keeps all generated artifacts for diagnosis.

drawing_preflightA

Validate and normalize requirements before committing a drawing plan.

drawing_planA

Commit a PlanSpec before any geometry is created.

The PlanSpec is stored on the backend and surfaced for reference during the workflow (it is not replayed as a critique). Always call this FIRST in a premium workflow.

drawing_critiqueA

Run premium-quality checks. Returns zero issues for a clean drawing.

Standard production gate: must return [] before drawing_finalize.

drawing_refineB

Run a bounded, transaction-safe critique/repair/re-critique loop.

point_from_snapA

Compute a deterministic snap point on an entity. Use this INSTEAD OF guessing coordinates — eliminates the most common LLM drawing error.

point_intersectionA

Compute the intersection of two geometry entities (LINE-LINE, LINE-CIRCLE, CIRCLE-CIRCLE). When two candidates exist, ref_x/ref_y selects the nearest. Returns {x, y}.

point_tangentA

Compute the tangent point on a circle from an external point. Returns {x, y}. Raises if the from-point is inside the circle.

construction_xlineA

Create an infinite construction line on the CONSTRUCTION layer. Use as scaffolding; call construction_clear() before finalize.

construction_clearA

Delete every entity on the CONSTRUCTION layer. Idempotent. Must be called before drawing_finalize to satisfy construction_left critique.

drawing_apply_iso_layersA

Bootstrap a full ISO-conformant layer set with correct colors and lineweights. Idempotent — existing layers are not modified.

Refused by name: a standard that is not one of mech, pid, iso13567, arch.

dimension_autoA

Generate ISO 129 dimensions across the listed entities in the chosen style. V1 supports LINE entities only.

entity_select_smartA

Select entities by semantic predicate instead of memorising handles.

Uncapped. The usual next step is dimension_auto(handles), so fields=["handle"] is normally all this needs to return.

gd_frameA

Draw an ISO 1101 feature control frame from LINE + TEXT primitives.

Renders identically on COM and ezdxf. Referenced datums are recorded so the gdt critique focus flags any datum with no matching datum feature.

datum_featureA

Place a datum feature symbol (filled triangle + boxed letter).

Establishes the datum so a feature control frame referencing this letter passes the gdt critique focus.

layout_listA

List all layout tabs (Model + paper-space layouts) and the current one.

layout_createA

Create a new paper-space layout tab.

layout_set_currentB

Activate a layout tab.

viewport_createA

Place a scaled model-space viewport on a paper-space layout.

The viewport window shows the model region centered at (view_center_x, view_center_y); view height = height / scale.

layout_deleteA

Delete a paper-space layout and every entity on it.

Refuses model space, a blank name, and the last remaining sheet. If the deleted tab was the current one, the returned current is where geometry goes next — and handles from the deleted sheet stop resolving.

layout_renameA

Rename a paper-space layout. Entity handles are unaffected.

layout_copyA

Copy a paper-space layout: page setup, plot settings and all geometry.

skipped names any DXF types that could not be cloned — check it rather than trusting ok alone. Associative hatch boundaries are re-pointed at the cloned entities; associativity_dropped counts those that referenced something outside the source layout and had to be cleared.

viewport_listA

List paper-space viewports: handle, geometry, scale and lock state.

The layout's own main viewport is included with is_main: true — it is the tab's pan/zoom state rather than a drafting viewport, and it is what remains after every drafting viewport is deleted. scale and locked are null on documents that cannot store them (R12) rather than fabricated.

viewport_set_scaleA

Rescale a viewport by adjusting its view height.

Geometric scale only: annotative text and dimensions do not resize with it. Refuses the layout's main viewport, whose view height is the tab's own pan/zoom state rather than a drafting scale.

viewport_lockA

Lock or unlock a viewport's display scale.

viewport_deleteA

Delete a viewport.

The layout's main viewport needs force=true; deleting it removes the tab's own view state, and the layout's current-viewport pointer is repaired so the file does not carry a dangling reference that only CAD would notice.

entity_change_spaceA

AutoCAD's CHSPACE: move entities across spaces, rescaled by the viewport.

Geometry is transformed by the viewport's own matrix so it stays the same size on screen — a move without that transform would leave a 100 mm feature as 100 mm of paper inside a 1:2 viewport.

Refused per entity for dimensions (unless freeze_dimensions), ACIS solids, tables and proxies, viewports, and entities already in the target space; refused outright for a twisted or non-plan viewport. Entities that end up outside the viewport or off the sheet are moved and flagged, not refused.

pid_symbol_listA

The symbols pid_symbol_insert can place, with their ports and variant options.

Authored from ISO 10628-2 (equipment, valves) and ISA-5.1 (instrumentation); each row's source names the figure. Symbol-local sizes are millimetres at A3/A1 paper scale (bubble Ø10, valve 8×4); scale at insertion rescales.

pid_symbol_insertA

Insert a catalogue symbol as a real block with TAG attributes and named ports.

Defines the block on first use (defined), creates a missing family layer from the P&ID layer set (layers_created), writes an ACADMCP_PID payload so readers without the catalogue still see the ports, and returns every port in WCS — connect them with pid_line_draw. An invalid ISA-5.1 tag is written and reported in tag_warnings; drawing_critique flags it.

pid_line_drawA

Connect two ports with one LWPOLYLINE on the class's layer.

Ports come from pid_symbol_insert; a bubble's radial port is entered without a name. auto picks the shortest orthogonal route that leaves each port straight for stub mm; when none exists the call refuses and says so — pass waypoints. crossings counts existing P&ID lines the new one cuts (reported, never refused) and port_reuse names ports that already had a line (branching is legal). Signal classes get ISA-5.1 markers (//, X, L, o) as small blocks on segments >= 15 mm; electric is dashed by layer. A signal line carries no pipe line number: it gets no auto-built number and no label, and does not consume the process sequence — a verbatim line_number is still written and labelled. With waypoints, a bubble's exit leaves towards the first waypoint (and the entry arrives from the last one); crossings follows existing arcs, not their chords.

pid_graphA

Connectivity of the drawing as it is, not as it was drawn.

Nodes: symbol INSERTs classified by catalogue name (confidence 1.0), ACADMCP_PID payload (0.95), tag attributes / block-name keywords (0.6) or a line touching an unknown INSERT (0.3); every node reports its source. Ports come from the INSERT's real rotation, scale and mirror, measured (a stretched bubble drops the node to 0.6 with a note). Edges: lines and polylines; each end resolves to a port, a junction on another line, or dangling with the nearest port as a hint — always within its own space, so scope="all" never joins two sheets. stats.confidence_min is the number to read before trusting a foreign drawing.

pid_instrument_indexA

Every instrument bubble with its ISA-5.1 reading and what it connects to.

Rows come from pid_graph, never from typed-in lists; the drawing is not modified. csv_path is the only file this tool writes.

pid_line_listA

Every P&ID line with its number, class, size/service/spec/insulation and endpoints.

Rows come from pid_graph; untagged lines sort last with line_number: null. The drawing is not modified; csv_path is the only file this tool writes.

pid_equipment_listA

Every equipment, valve and connector node with its ports and how many lines reach them.

Rows come from pid_graph; the drawing is not modified and csv_path is the only file this tool writes.

pid_from_specA

Equipment, valves, instruments and connectors placed, then every line drawn port-to-port, inside one transaction: any bad item rolls the whole sheet back and the error names it (lines[2].to); so does an interruption (a client cancellation mid-run leaves no half-drawn sheet and no open transaction on either engine — the live one goes back to the UNDO Mark transaction_begin set, so it never waits at an AutoCAD prompt; should that rollback itself fail, the failure is logged, the cancellation is what the client sees, and the drawing must be checked before a retry). A non-finite coordinate, rotation, scale or stub is refused by path before anything is placed. The response carries the graph read back from the drawing and the P&ID critique issues, so the caller sees dangling ends or duplicate tags in the same round trip. dry_run returns the planned vertices and crossings without touching the drawing.

pid_tag_parseA

ISA-5.1-2009 Table 4.1 as a grammar: first letter, modifier, readout and output functions, trailing high/low, loop number and suffix — with the standard's description ("Flow Indicating Controller") or the first offending letter. Equipment prefixes are not standardised, so the default map (P pump, V vessel, E exchanger, ...) can be replaced per call.

dimstyle_listA

Every DIMSTYLE table entry with the seventeen preset variables (DIMTXT, DIMASZ, DIMEXE, DIMEXO, DIMGAP, DIMTAD, DIMTIH, DIMTOH, DIMDEC, DIMDSEP, DIMLUNIT, DIMZIN, DIMBLK, DIMTXSTY, DIMLWD, DIMLWE, DIMSCALE).

Headless, values is what the DXF stores (the schema default where an entry omits a code). On the live engine ActiveX has no per-style getters, so values is read for the current style only and the other rows carry values: null, values_available: false — dimstyle_set_current a style to read it. Never refuses on an open drawing.

dimstyle_createA

Create a dimension style: preset values first, then overrides.

Refuses, before anything is written: an unknown preset; an override key outside the 33-variable whitelist (the 17 preset variables plus DIMTOL, DIMTP, DIMTM, DIMTOLJ, DIMTFAC, DIMLFAC, DIMRND, DIMATFIT, DIMTMOVE, DIMCLRD/E/T, DIMSAH, DIMBLK1/2, DIMCEN); a value outside its range (DIMDEC 0-8, sizes > 0, DIMTAD 0-4, DIMDSEP one character, lineweights an AutoCAD code); a name that already exists (use dimstyle_modify); a user DIMBLK/DIMBLK1/DIMBLK2 naming a block the drawing does not define (built-in arrowheads need none); a DIMTXSTY that is neither an existing text style nor a bundled preset (ISOCP, ISOCPEUR, ARIAL, ROMANS — those are created on both engines, textstyle_created; live, a preset whose font file the seat lacks is refused the same way, nothing written). On the live engine a write ActiveX still refuses after the style is added is rolled back — previous style current, the half-made entry deleted. With set_current the next dimension carries the style on both engines.

dimstyle_modifyA

Change variables on an existing dimension style.

changed names only the variables that actually moved — re-setting a value to itself is not a change. dimensions_using_style lists the dimensions already drawn with it; headlessly rerender_required: true says they still show the old style until redrawn (AutoCAD re-renders on the next regen). Refuses a missing style, an empty overrides, a key outside the whitelist, a value outside its range, a DIMTXSTY that does not exist, a user arrowhead block the drawing does not define — all before any write. On the live engine, editing a non-current style makes it current for the duration of the call and the previous style is restored — also when a write fails midway (its unsaved overrides are discarded, which is AutoCAD's own DIMSTYLE rule).

dimstyle_set_currentA

Set $DIMSTYLE and load the style's variables as the current DIM* settings — what a live seat's DIMSTYLE Restore does — so dimension_* and dimension_auto draw with it on both engines. Per-dimension tolerances, fits and text overrides still apply on top. Refuses a style the drawing does not hold. Returns previous and changed.

textstyle_listC

Every STYLE table entry and the one new TEXT/MTEXT will use.

textstyle_createA

Create a text style.

Headlessly a font nobody can find is written and reported font_resolved: false (AutoCAD substitutes at open; the headless renderer falls back), because a DXF stores only the name. The live engine cannot do that: ActiveX refuses a font AutoCAD cannot open, so a file that is neither on its support path nor in the Windows Fonts folder is refused there before any write (the message names the folders and the presets); a TrueType font is written by its typeface (SetFont, what the STYLE dialog does — the record carries arial.ttf, never a machine path), an SHX by the file name. Refuses, before any write on both engines: a name that exists, an empty font, width_factor <= 0, height < 0, an oblique angle outside ±85°.

textstyle_set_currentA

Set $TEXTSTYLE; entity_create_text / entity_create_mtext then carry the style on both engines. Refuses a style the drawing does not hold. Returns previous and changed.

mleaderstyle_listA

Every MLEADERSTYLE with its four values on both engines (values_available: true). Headless they are read from the MLEADERSTYLE object; live from the AcadMLeaderStyle objects the ACAD_MLEADERSTYLE dictionary holds (ActiveX exposes no collection property for them, but the dictionary items are full objects). leader_create_mleader can still override any of them per leader.

mleaderstyle_createA

Create a multileader style: preset values first, then overrides.

Headless it lands on doc.mleader_styles; live it is added through the ACAD_MLEADERSTYLE dictionary (AddObject(name, "AcDbMLeaderStyle")) and the object's properties are written. Refuses, before any write: an unknown preset; an override key outside the four; arrow_size / text_height <= 0, landing_gap < 0; a name that exists; a text_style that is neither present nor a bundled preset (ISOCP, ISOCPEUR, ARIAL, ROMANS — those are created on both engines, textstyle_created; live, a preset whose font file the seat lacks is refused, nothing written).

drawing_apply_standardA

One call for the common case: the standard's dimension style (created if missing, then current), its text style (created if missing, then current), the shared units, and with layers the mech layer set (ANSI layer naming is company-specific, so both standards share it).

Every item reports created or already present; settings.changed names only the variables that moved, so a second call reports nothing. An existing ISO-25 / ANSI style is reused as it is, not reset — use dimstyle_modify to change one. Refuses an unknown standard, or a units variable it cannot read back, before any write; the underlying style refusals (dimstyle_create, textstyle_create) apply unchanged. In the lean profile (Task 13).

page_setup_listA

The page setup stored on each paper-space layout.

paper is the catalogue name (ISO_A3, ANSI_B, …) when the stored size matches one within 0.5 mm, otherwise the media name as stored; size_mm, orientation, plot_style (ctb), scale ("fit", "1:50", or a custom ratio), plot_area, device, margins_mm [top, bottom, left, right] and center are read back from the LAYOUT object (headless) or the AutoCAD Layout (live). Refuses an unknown layout name and Model (model space has no sheet; plot it with drawing_export_pdf(layout=None)).

page_setup_applyA

AutoCAD's PAGESETUP as one call, on both engines.

Paper sizes are ISO 216 / ANSI Y14.1; the media is written in AutoCAD's own spelling (ISO_A3_(420.00_x_297.00_MM)). changed lists only the values that moved — re-applying the same setup reports {}. An unknown ctb is written and reported plot_style_known: false (a missing ctb only matters at plot time). Viewports on the sheet are never touched.

Refused before anything is written: an unknown paper, orientation, scale or plot_area, an empty device or plot_style, margins that leave no printable area, Model, an unknown layout. On the live engine margins_mm is refused (the .pc3 owns them) and a media the device does not offer is refused with the device's names for the same paper.

The proof is the PDF: batch_plot reads each sheet's /MediaBox back.

plot_style_listA

The ctb files AutoCAD ships (monochrome.ctb, acad.ctb, Grayscale.ctb, the Screening set, …) and, on the live engine, the files actually present in Preferences.Files.PrinterStyleSheetPath (source: "installed", installed: true/false per row). Headlessly installed is null: there is no installation to scan, and the catalogue is not evidence of one. Never refuses; an unreadable Preferences object degrades to the catalogue.

batch_plotA

AutoCAD's PUBLISH for a PDF set, through drawing_export_pdf(layout=…).

One row per sheet: path, bytes, and mediabox_mm parsed from the PDF that was written (/MediaBox, points → mm), with paper naming the catalogue size it matches within 0.5 mm — so the sheet size is verified, never assumed. Model space is included only when named.

Refused before any file is written: a format other than pdf, an empty layouts list, a layout that does not exist, a file_pattern containing a path separator or lacking {layout} when more than one sheet is plotted, and any output path outside the allowed directories. A sheet whose PDF has no readable MediaBox is reported with mediabox_mm: null and an error.

drawing_template_listA

The templates drawing_new(template=<name>) can start from.

Each row: standard (ISO/ANSI), sheet, paper, layout (the sheet tab's name), layer_set (mech / pid / iso13567), dimstyle / textstyle (ISO-25 / ISOCP or ANSI / ROMANS), scale, title_block (the ISO 5457 A3 frame, A3 sheets only), the settings applied, and files.dxf / files.dwt with present flags — the .dwt twins exist only once built on a live AutoCAD (scripts/smoke_settings_com.py --build-dwt). Never refuses; it reads a catalogue.

drawing_template_saveA

AutoCAD's SAVEAS → Drawing Template, on both engines.

Live AutoCAD writes a real .dwt (SaveAs(path, ac2018_Template)) and puts description into the template's summary Comments; the active document is rebound to the new file, as SAVEAS does. Headlessly a .dxf template is written — drawing_new(template=<path>) opens it — and a .dwt request is refused with capability dwt_write (the message names the DXF route and the COM route); a description is reported description_written: false because DXF has nowhere to keep it. Any other suffix, and any path outside the allowed directories, is refused before a byte is written.

Pack: core · lean: no (drawing_save_as is not lean either).

document_listA

Every open document with name, path, active, saved and entity_count.

Headless, the server keeps its own registry: drawing_new / drawing_open add an entry (untitled-N or the file path) instead of replacing the only one, and document_activate chooses which one every later tool targets. Live, this is AutoCAD's Documents collection. No refusals: an empty backend answers with an empty list. Pack: settings · lean: no.

document_activateA

Make one open document the active one; reports previous.

Matches the full path first, then the file name; an ambiguous name is refused with the candidates, an unknown one with the list of open documents. Headless, a document quarantined after an abandoned call cannot be switched away from — drawing_new, drawing_open or closing it are the ways out. Pack: settings · lean: no.

document_closeA

Close a document and report saved, discarded_changes and the new active.

Refusals, all before anything is closed: unsaved changes with neither save nor discard; save on a document that has never been saved (no path to write — live, Close(True) would open AutoCAD's Save dialog and block the COM thread); save together with discard. Closing the last document leaves the backend with none open, which every tool already reports. drawing_close is the same operation for the active document with its 1.4 contract kept. Pack: settings · lean: no.

layer_state_saveA

Snapshot every layer's on/frozen/locked/color/linetype/lineweight/plot flags plus the current layer as a named state stored in the drawing.

These are the server's own portable layer states: JSON chunks in an XRECORD under the ACADMCP_LAYERSTATES dictionary. They live in the file and travel with it, work on both engines, and do not appear in AutoCAD's Layer States Manager (LAYERSTATE). Same name replaces (replaced: true). Refusals: an empty or control-character name, a non-string description. Pack: settings · lean: no.

layer_state_restoreA

Apply a saved state to the layers that still exist.

missing_layers (in the state, not in the drawing) are skipped, never created; new_layers (in the drawing, not in the state) are untouched; applied says how many layers and which properties moved. Refusals: an unknown state name (lists the saved ones), a property outside the eight (names the index). Live, a layer AutoCAD refuses to change (freezing the active layer, making a frozen layer current) lands in warnings instead of failing the call; the state's current layer is thawed before it is made current when frozen is being restored, so save → freeze → restore round-trips. Portable server states, not Layer States Manager entries. Pack: settings · lean: no.

layer_state_listA

Every state under ACADMCP_LAYERSTATES with its description and layer count. These are the server's portable states, not AutoCAD Layer States Manager entries. No refusals. Pack: settings · lean: no.

layer_state_deleteA

Remove the named state's XRECORD. Layers themselves are untouched. Refusal: an unknown name (lists the saved ones). Pack: settings · lean: no.

view_named_saveA

Store a VIEW table entry (AutoCAD's VIEW command). Same name replaces (replaced: true). Refusals: height/width ≤ 0 or non-finite, a malformed center, and headless an empty drawing with no center/height (there are no extents to default to). Pack: settings · lean: no.

view_named_restoreA

Live: zooms the active viewport to the saved window the way -VIEW _R does — VIEWCTR becomes the saved centre and VIEWSIZE the saved height (or width / display aspect when the window is wider than the display); applied: "zoom_window" plus the read-back viewctr / viewsize. Headless there is no display: the saved window is fitted into the *Active VPORT — the view AutoCAD opens the file on — whose aspect ratio is left as the file carries it (AutoCAD reconciles a changed aspect by the viewport's lower-left corner, which shifts the centre); the result says applied: "header_only" with the written vport_height and the kept aspect_ratio, the same reported-no-op rule as view_zoom_extents. Refusal: an unknown name (lists the saved views). Pack: settings · lean: no.

view_named_listB

Every VIEW table entry with centre, height and width. No refusals. Pack: settings · lean: no.

ucs_listB

The world row first, then every UCS table entry with origin and unit axes, current on the active one. world is current only when the frame IS the WCS (WORLDUCS live, the $UCS* header headless) — an unnamed UCS (UCS Origin / 3P without saving) has an empty name too and is reported as a trailing row with name: null and its origin/axes, so current is null then and never world. Tool coordinates stay WCS on both engines whatever is current. No refusals. Pack: settings · lean: no.

ucs_setA

Store a UCS table entry and make it current (AutoCAD's UCS command).

Axes are normalised to unit vectors. Every tool keeps taking and returning WCS coordinates — the repository rule; a UCS is for the operator's own drafting, and no tool starts interpreting inputs in it. Refusals, before any write: a name of world (reserved), a zero-length axis, and non-perpendicular axes — the message carries the measured angle (tolerance 0.001°). Pack: settings · lean: no.

ucs_restoreB

Live: ActiveUCS for a named entry; world runs UCS World, which is refused while AutoCAD has an active command (CMDACTIVE — press ESC). Headless: the $UCSNAME/$UCSORG/$UCSXDIR/$UCSYDIR header variables. Refusal: an unknown name (lists the saved ones). Tool coordinates stay WCS. Pack: settings · lean: no.

system_launchA

Connect to the application named by CAD_PROGID (attach if running, launch otherwise) and report launched, attached, version and the active document. Refusals: headless, capability: "live_application" (there is no application to launch); an open_path that fails path validation. Pack: settings · lean: no.

system_preferences_getA

The whitelisted Preferences.* values, enum values as names (SaveAsType: "ac2018_dwg"), with read_only naming the four Files.* paths. Refusals: headless, capability: "preferences" (they live in the running application, not in a file); a key outside the whitelist. Pack: settings · lean: no.

system_preferences_setA

Write one preference and report old, new and changed.

Refusals, all before any write: a read-only key (Files.*), an unknown key, a value of the wrong type, an int outside the authored range (AutoSaveInterval 0–600 min, CursorSize 1–100, PickBoxSize 0–50, …), an unknown SaveAsType name; headless, capability: "preferences". Pack: settings · lean: no.

user_pick_pointA

Utility.GetPoint: returns the WCS x, y (z) the operator clicks.

ESC is an answer, not an error: cancelled: true with AutoCAD's reason. Waiting longer than COM_CALL_TIMEOUT returns timed_out: true (the prompt is abandoned on AutoCAD's side; press ESC there). Refusals: an empty prompt; headless, capability: "interactive_prompt" (no operator). Pack: settings · lean: no.

user_selectA

Returns handles the operator picked — one with mode="single" (plus the picked point [x, y] in WCS — AutoCAD reports it in the current UCS and the tool translates, so a UCS made current by ucs_set never shifts it), any number with mode="multiple" (Enter with nothing selected is count: 0, not a cancel). ESC → cancelled: true; a wait longer than COM_CALL_TIMEOUT → timed_out: true. Refusals: a mode outside the two, an empty prompt; headless, capability: "interactive_prompt". Pack: settings · lean: no.

system_prompt_messageB

Utility.Prompt: tell the operator something where they are looking. Nothing in the drawing changes. Refusals: an empty message; headless, capability: "interactive_prompt". Pack: settings · lean: no.

system_variable_describeA

What an AutoCAD system variable means, from an authored catalogue of 90.

With name: {known, name, type, range|enum, default, meaning, saved_in (drawing|registry|not_saved), engines: {ezdxf, com}, friendly_key, read_only} plus current when the active backend can read it (omitted, with current_unavailable, when it cannot — no document open, or a registry variable headlessly). An unknown name is never an error: known: false and the nearest catalogue names come back. With search: every row whose name or meaning contains all the words. With neither: the index of names. friendly_key names the drawing_settings key that wraps the variable, which is the preferred way to set it; engines.ezdxf: false means the headless engine refuses a write (registry-saved, or no header slot in ezdxf).

drawing_properties_getA

The DWGPROPS dialog as data: summary (title, subject, author, keywords, comments), summary_available, and custom ({key: value}).

On the live engine the summary comes from the document's SummaryInfo. The headless engine cannot read that stream, so the five summary fields are null with summary_available: false — not empty strings, which would claim the drawing has no title. Custom properties ($CUSTOMPROPERTYTAG / $CUSTOMPROPERTY header pairs) are read on both engines.

drawing_properties_setA

Write DWGPROPS fields. Only the arguments given are touched; returns summary_written, custom_written and custom_deleted (a key that was never there is not reported deleted).

Refusals, before anything is written: a summary field on the headless engine (capability: dwgprops — SummaryInfo lives in the DWG, a DXF has no slot for it; custom properties still work headlessly), a non-string value (TypeError naming the field or key — nothing is coerced with str()), an empty custom key, a custom key to write that AutoCAD's AddCustomInfo would reject mid-write (measured on AutoCAD 2026: leading or trailing whitespace, or any of the thirteen characters " * , / : ; < = > ? \ |anywhere in the key; internal spaces, tabs and unicode are fine —ValueErrornaming the key, on both engines; a delete is exempt because RemoveCustomByKey never validates syntax, so a key that reached the drawing another way stays removable), two keys in one request that AutoCAD would call the same key (its key compare is a simple per-character case compare:Project/PROJECTandGrün/GRÜNare one key,Straße/STRASSE are two), a line break in a custom key or value (it corrupts the DXF on save), and headlessly a document older than R2004 (ValueError` — ezdxf only writes the custom-property header pairs for AC1018+, so they would vanish at save; save as R2004 or newer first). A key is matched to the drawing by that same rule on both engines and keeps its stored spelling when updated. On the live engine an exact spelling is changed with SetCustomByKey; otherwise AutoCAD decides — AddCustomInfo, and on its 'Duplicate key' SetCustomByKey; a delete is RemoveCustomByKey, and its 'Key not found' is reported as not deleted.

mech_part_drawA

One part model - a turned profile or a plate outline plus typed features - drawn as views.

The model is written onto the drawing as ACADMCP_MECH XDATA on an anchor POINT, so mech_view_add can add a section months later without the caller re-describing the part, and mech_part_inspect reads it back.

Refused before anything is drawn, by path: a non-finite or non-positive number (segments[2].d_outer), a bore that is not smaller than its outside, an outline with fewer than three distinct vertices or one that crosses itself, an unknown material, a feature whose placement is off the part, two features that would remove the same material (both names given), a thread outside the transcribed ISO 261 table, a keyway outside DIN 6885's bore range, gear teeth whose tip diameter disagrees with their segment. A DIN 509 undercut, a DIN 471/472 groove, a DIN 332 centre hole and an ISO 3601-2 O-ring groove need explicit dimensions in this build: those tables are not transcribed and the lookup refuses by name rather than interpolate. A feature that cannot be projected into a requested view is listed in omitted, never dropped.

mech_view_addA

Another view of a part already on the drawing, laid out on its projection axis.

The part model comes back out of the drawing's ACADMCP_MECH XDATA, so the caller never re-describes it, and the placement follows the projection angle recorded when the part was drawn (first angle by default: the view from the right goes to the left).

Refused by name: a section without a plane, or with a plane of zero length, a plane that misses the part, or one that grazes an outline vertex so its crossings cannot be paired; a half or offset section on the wrong kind of plane (the message names the style that does apply); a detail without a radius or with a scale of zero; an unknown part_id, and part_id=None on a drawing that holds more than one part.

mech_dimension_partA

Every dimension the part and its features ask for, laid out without overlaps.

Axial lengths are chained, stacked from a baseline or measured from an origin; diameters stack outside the silhouette; fillets get a radius. Each measurement appears once (ISO 129-1): every view record carries a dimensioned flag, so after a mech_part_draw that dimensioned the front view and a mech_view_add, this call dimensions only the new view, and views naming a view already dimensioned is refused by name. fits resolves an ISO 286 code against the measured nominal through the repository's authored tables and appends the code to the dimension text; an explicit tol on a feature's own intent does the same through the ISO 129 path.

Refused by name: a fit together with an explicit tolerance, a fit outside the authored ISO 286 range (over 1 mm to 500 mm, IT4-IT11), a fit on an intent with no measurable nominal, an unknown style, an unknown part_id, a call when every view is already dimensioned (the message lists them), and part_id=None on a drawing that holds more than one part. An angular intent is reported in skipped rather than drawn, because a DimIntent carries no vertex.

mech_hole_patternA

A hole pattern on any drawing - the part model is not required.

The same expansion HolePattern performs inside a part, exposed for a drawing that was not built from the model.

Refused before anything is drawn: an unknown pattern, a count below 1 (below 2 for polar), a linear pattern with no spacing, a grid with more than one column or row and no pitch for it, a polar pattern with no pitch-circle diameter, and a non-finite or non-positive diameter.

mech_part_from_specA

Several parts, their views and their dimensions, drawn inside one transaction.

Every part is validated before the transaction opens, so a refusal leaves the drawing untouched and names the offending path (parts[1]: segments[0].d_outer: ...). If a draw fails or the request is cancelled part-way, the transaction is rolled back under an anyio shield, so a cancelled call cannot leave half a sheet inside an open transaction.

Refused by name: an empty parts list, any part refusal from mech_part_draw, and a transaction that cannot be opened.

mech_part_inspectA

The ACADMCP_MECH payload a drawn part carries, decoded.

Never modifies the drawing. Returns the part model exactly as mech_part_draw accepts it (part), the views drawn so far with their placements, and the payload version.

Refused by name: an unknown part_id, a handle that carries no ACADMCP_MECH payload, a corrupt or foreign payload, and part_id=None on a drawing that holds no part or more than one (the message lists the handles).

std_part_listA

Catalogue rows with the dimensions a drawing needs, and their provenance.

Every row is transcribed from the named standard's own table and carries its source. Coverage is deliberately narrow: ISO 261 first-choice sizes only (M5-M36, M3-M24 for ISO 4762) and ISO 15 bore numbers 00-10 in the 600x / 620x / 630x series. A size outside a table is refused by name by std_part_insert with the nearest entries, never interpolated. An unknown standard is refused with the list of catalogue standards.

std_part_insertA

Define the part's block once, insert it, and write its std_part XDATA.

The block carries DESIG / STD / SIZE / MAT attributes and an ACADMCP_MECH payload, so a parts list is a read of the drawing rather than a naming convention. Refusals, all before any write: a designation outside the transcribed tables (named, with the nearest catalogue entries - nothing is drawn approximately), a malformed designation, a missing or stray nominal length, a view the family does not have, an attribute tag the block does not carry, and a non-finite coordinate or rotation.

std_feature_drawA

Add a standard feature to geometry that already exists - a foreign drawing being finished.

Local frame: (x, y) is on the axis, +X runs along the axis in the direction the feature extends and +Y is radially outward. The thread is the ISO 6410 representation (minor diameter at 0.8 x major, thread-length limit to the major) and its pitch comes from ISO 261 via size or from an explicit pitch - it is never guessed. Every other kind takes its dimensions from the registered standards table and is refused by name when that table is absent, when the size is outside its coverage, or when the row lacks a dimension the feature needs: no value is interpolated and no profile is reconstructed. DIN 332 form R is refused - only forms A and B are drawn.

surface_textureA

Draw the 60° surface-texture vee with its annotation in the standard positions.

Refusals, all before the first entity reaches the drawing: a text height outside the seven ISO 1302 rows (2.5/3.5/5/7/10/14/20 mm — never interpolated), a lay that is not one of the seven ISO 1302 directions of lay, a machining outside any/required/prohibited, and a standard other than ISO 21920-1 or ISO 1302.

weld_symbolA

Draw an ISO 2553 weld annotation: reference line, identification line, symbol, dimensions.

Refusals, all before the first entity reaches the drawing: a kind outside the six elementary symbols transcribed here (square, v, bevel, u, j, fillet — the rest of the ISO 2553 table is deliberately not shipped rather than guessed), a side outside arrow/other/both, a non-positive height, and a pitch given without a length.

centre_marksA

Centre marks on the CENTER layer, whose linetype carries ISO 128-23's dash pattern.

Pass handles and the radii are read back with entity_get rather than restated — a radius from memory is the classic silent wrong number. Refusals, all before the first entity is written: neither handles nor centers given (or both), a handle that is not a CIRCLE or ARC, a circle in a plane tilted out of WCS XY (capability ocs_tilted_plane, so it has no radius in this frame), a style outside mark/lines, a non-positive extension, and style='lines' on a centre given without a radius.

section_lineA

Draw the cutting-plane line and hand back the plane a section view consumes.

Wide segments at the ends on GEOMETRY, the thin long-dash-dot middle on CENTER, an arrow at each end whose head sits on the line end and points the way the section is viewed, and the same letter beyond both arrows. payload["plane"] is exactly {p1, p2, label, direction, style} — feed it to the section view so the label on the plan and the label on the view cannot disagree. Refusals, before any entity is written: p1 == p2, a zero or parallel viewing direction, an empty label, a style outside full/half/offset/revolved, and a non-positive height.

hatch_materialA

Section-hatch a cut face with the pattern ISO 128-50 gives its material.

Refusals: an unknown material (named, with the full list, before anything is drawn), neither boundary nor handles (or both), a boundary with fewer than three points, and a non-positive scale. With handles the loop is chained by boundary_from_entities, which the COM engine refuses (capability boundary_trace) - pass boundary on a live seat, or run headlessly. The HATCH layer is created first when the drawing lacks it: ActiveX refuses an entity on an absent layer and would otherwise leave the hatch orphaned on layer 0.

The payload states its own accuracy, as analysis_measure_entity does: area is the polygon actually hatched, boundary_area the exact area of the chained loop, and accuracy is "exact" or "flatten_tolerance" - an arc edge reaches entity_create_hatch as chords, so a curved cut face is hatched to within HATCH_FLATTEN_SAGITTA of itself rather than being replaced by its chord polygon. With handles, the outline boundary_from_entities draws is scaffolding and is deleted; traced reports its handle and whether the delete succeeded. A loop enclosing no area is refused instead of writing a HATCH of area 0.0.

sheet_frameA

ISO 5457 drawing frame for A4-A0: a 20 mm filing margin, 10 mm on the other three edges, the grid reference system and the centring/trimming marks.

Borders, rules and marks land on TITLEBLOCK; the zone lettering on TEXT. Refusals, all before the first entity is drawn: a size outside A4-A0 is refused by name and the five covered sizes are listed; an orientation that is neither 'landscape' nor 'portrait'; a layout that does not exist. The zone divisions drawn are equal -- ISO 5457's shorter corner fields are not implemented -- while the division counts are the standard's.

titleblock_applyA

ISO 7200 title block, 180 mm wide, in the lower-right corner of any A4-A0 sheet. The title text is used verbatim.

Carries the ISO 128-30 projection-angle symbol: 'first' draws the cone on the left and the concentric circles on the right, 'third' is its mirror. Refusals, all before the first entity: an unknown size (the five covered sizes are listed), an unknown orientation, a projection that is not 'first'/'third'/'', a layout that does not exist. titleblock_apply_iso_a3 is this tool with size='A3' and no symbol, kept so no caller breaks.

revision_addA

Append one row to the revision block, creating the block on first use.

Idempotent per revision code: a code the drawing already carries returns created=false and draws nothing, so re-running a revision pass cannot stack duplicates. The block defaults to the upper-right corner of the drawing frame, growing downwards, so it does not collide with the ISO 7573 parts list above the title block. Refusals, all before the first entity: a malformed code, a cloud region that is not [x0, y0, x1, y1], and any request for clouds on a backend whose revcloud capability is false (the COM engine — REVCLOUD has no ActiveX member) — that one carries capability: "revcloud".

bom_extractA

Walk the INSERTs and return the ISO 7573 item rows. Never modifies the drawing. bom_table is what draws them.

Each row's source is reported: xdata when the ACADMCP_MECH payload supplied it (what std_part_insert writes), attributes when the block's own ATTRIBs did. A block with neither a payload nor a DESIGNATION attribute is skipped rather than guessed at, and skipped counts them.

The whole drawing is read by default — entity_list's 200-entity page is paged through, not taken as a cap, because an item list that stops at the 200th INSERT prints a wrong QTY rather than a shorter one. Pass limit to cap it deliberately; truncated is then true if and only if the cap cut the list. Refusals: an unknown column or group_by field, named with the list of the ones there are.

bom_tableA

Draw the ISO 7573 item list as a real TABLE entity, 180 mm wide (the title-block width), growing upwards from directly above the title block.

With direction="up" the heading row sits against the title block and item 1 is the row above it, so the list extends upwards as parts are added — which is what ISO 7573 asks for on a drawing. Pass rows to draw a list you already have, or omit it and the tool runs bom_extract first. representation reports what was drawn: native (a real ACAD_TABLE on the live engine) or composite (rules and MTEXT headlessly, whose handle is the first child). Refusals: no rows to draw, an unknown column, an unknown direction, a layout that does not exist.

balloon_addA

One ISO 6433 item reference: a numbered balloon, a leader, and a dot on the item.

The balloon carries an ACADMCP_MECH payload naming its targets, so running the balloon pass again after the bill of materials is regrouped renumbers the existing balloon (renumbered: true) instead of drawing a second one. Refusals, all before the first entity: an item number below 1, a leader target inside the balloon, and an item number already used by another balloon for different targets — named with that balloon's handle.

xref_attachA

Attach an external reference and insert it once. Both engines.

The block takes the referenced file's stem as its name. Refusals, all before anything is written: a kind that is not 'attach' or 'overlay', a file that does not exist, a non-positive or non-finite scale, and a block name the drawing already holds — detach it first with xref_manage(action='detach').

xref_manageA

One operation on one external reference.

list, detach and path work on both engines. reload and bind need a live AutoCAD seat's xref manager: headlessly they are refused with capability: "xref_live" rather than pretended, and the refusal says which engine does them. Other refusals: an action outside the five, an unknown xref name, a 'path' action with no new_path. On the live engine a listed row's inserts and kind are both null — ActiveX's block interface carries neither a per-xref insert count nor an overlay indicator, and this server does not invent them. Headlessly both are measured: inserts counts every insert in the drawing, model space and paper space alike, and detach removes exactly those.

image_attachA

Attach a raster underlay at the file's own aspect ratio. Both engines.

scale is drawing units per pixel, so the placed size is the image's pixel size times scale and the payload reports both. Refusals, all before anything is written: a file that does not exist, a file no image reader can open (named), a non-positive or non-finite scale.

data_extractA

The same rows bom_extract returns, written to a file.

Refusals: a format that is not 'csv' or 'xlsx'; a drawing with nothing to itemise (nothing is written); and fmt='xlsx' without openpyxl, which carries capability: "xlsx_write" and names both the package to install and the CSV route that always works.

drawing_export_dwgA

Write a real DWG — not a DXF under a .dwg name.

On a live AutoCAD seat this is Document.SaveAs with the matching AcSaveAsType, which (as AutoCAD's own SaveAs does) leaves the session bound to the file it just wrote. Headlessly it needs the ODA File Converter; when that is absent the call is refused with capability: "dwg_write" and the refusal names the install route and drawing_export_dxf, which writes a DXF AutoCAD opens unchanged. Check system_capabilities first: the ezdxf flag is re-evaluated at call time, so installing the converter changes it without a restart. An unknown version is refused by name with the six.

arch_wallA

Add walls to the plan network already on the drawing and resolve every junction.

Two ends at one point mitre into a clean L; an end inside another wall is a T (the stem stops on the crossing wall's near face, which is cut there); two axes crossing are an X (all four faces cut). A drawn wall whose outline the new walls change is taken back out and redrawn with its openings - the result lists it under redrawn - and a wall they do not touch is left alone. Every wall carries an ACADMCP_ARCH record, so later calls find it by id.

Refused before anything is drawn or erased, by path: a wall id already on the drawing or used twice, an axis of fewer than two points or with a zero-length segment, a non-positive thickness, an unknown justification or material (the list is named), two walls meeting at less than 5° (the mitre would run away), a wall corner lying inside another wall off its axis, an end inside a wall whose axis only meets it past that wall's end, and a new wall that would leave a drawn opening uncuttable. A curved wall is not supported: an axis is straight segments only.

arch_openingA

A door or a window in a wall already drawn, found by its id; the wall is redrawn cut.

The opening removes its width from both wall faces and each edge is closed by a jamb. A door is drawn open at 90° - its leaf as long as the opening is wide, hinged on hand, with a quarter-arc swing on the swing side; a window is a frame line on each face and two glazing lines between them. The opening's ACADMCP_ARCH record sits on the leaf or the frame, so a schedule reads it back.

Refused before anything is drawn or erased: a wall id not on the drawing (the drawn ids are named), an opening id already drawn, an opening that runs past its wall segment or straddles an axis vertex, one overlapping another opening on the same wall (both ids named), one that runs into a junction (the solid stretch it must fit in is named), an unknown kind, swing, hand or language.

arch_stairA

A stair in plan: every riser as a line, the outline, the walking line with its arrow.

The label ("UP" / "ÇIKIŞ") sits on the first tread at 2.5 mm × scale. The result reports blondel - 2R + G against 600-650 mm, the step-length rule attributed to François Blondel (1675). It is a design rule reported for the drafter, not a building code: no national stair regulation is checked and a value outside the band is reported (ok: false), not refused.

Refused before anything is drawn: a stair id already on the drawing, a non-positive width, riser height or going, fewer than 2 risers (4 for an L or a U - two per flight), a non-integer riser count, an unknown kind, turn or language.

arch_dimension_chainsA

The three exterior chains an architectural plan carries, as real DIMENSIONs.

Nearest first: the openings row (every jamb in that facade), the walls row (both faces of every wall meeting it - wall thickness, clear width, wall thickness, ...) and the overall row. The points come from the wall engine's own faces, read back from the plan on the drawing. A row that would only restate a farther one is not drawn (ISO 129-1: each measurement once). The row spacing defaults (10 mm, then 8 mm on paper) are this server's drafting choices, not standard values. Text, arrows and gaps follow the plot scale: each chain is drawn at DIMSCALE = scale (reported as dimscale), and the drawing's own DIMSCALE is put back afterwards.

Refused by name: a drawing with no walls, an unknown or repeated side, a non-positive scale, offset or step.

arch_roomA

Label the room around (x, y) with its name, number and MEASURED area.

The area is never typed: the tool reads the wall faces on the wall layer of the arch set (LINE and lightweight polyline, both engines; anything else there is listed in skipped), finds the closed face the point lies in and writes that face's area - net of the wall thickness and of any column inside it - into the label and into an ACADMCP_ARCH room record on the name text, which arch_schedule reads. A door or window recorded on the drawing closes its gap along the wall faces, so two rooms either side of a door stay two rooms.

Refused before anything is drawn: an unknown lang (named with en, tr), a number/name the room model refuses, a room_id already labelled on the drawing, a point in no closed face of the walls (draw or close them first, or read a plan drawn by other means with arch_rooms_detect), a point inside a wall body, and a point in a room that already carries a label (one face, one room record - a retried call does not add a second area to the schedule).

arch_rooms_detectA

Read the rooms of a plan - ours or a foreign one made of plain lines.

Every LINE and lightweight polyline on the layers is split where lines cross or touch, and the closed faces they bound are measured (mm², net of nested pieces). Faces under min_area, and thin faces (mean width under 600 mm - wall bodies and reveals, this reader's heuristic) are left out. Each room reports confidence: 1.0 when every edge lies on the arch wall layer, 0.6 when any edge is a plain line from elsewhere - read confidence_min before trusting a foreign plan. Room labels already on the drawing are reported in labels with the face they sit in; a face with more than one is listed in label_conflicts.

Never modifies the drawing. Arcs and bulged polyline edges, old-style POLYLINEs and block references are listed in skipped with their handle and reason - never flattened into chords, never dropped silently. Read skipped before trusting count. A foreign plan's open doorways are not closed - two rooms joined by one read as one face. Refused: a named layer the drawing does not have (with the list of the ones it has), and no layer matching WALL or DUVAR when layers is omitted.

arch_scheduleA

Draw a door, window or room schedule as a real TABLE - a read of the drawing.

The rows come from the ACADMCP_ARCH records on the drawing (what arch_wall / arch_opening / arch_room write), never from the caller: doors by tag with width, height, swing, hand and wall; windows by tag with width, height, sill and wall; rooms by number with name and the measured area, plus a total. An opening drawn without a tag gets the next free D1 / W1 (K1 / P1 in Turkish) in wall order; an explicit tag is kept. A value the model does not carry is an empty cell, never a default. representation reports what was drawn: native (ACAD_TABLE, live) or composite (rules and MTEXT, headless).

Refused before anything is drawn: an unknown kind or lang (named with the list), nothing of that kind on the drawing, and more rows than one TABLE takes (198).

arch_catalogue_listA

Catalogue rows: name, family, both labels, nominal size [w, d] in mm, block name, layer.

Sizes are nominal catalogue dimensions - what a furniture or appliance catalogue lists as a common size - and every row says so in size_basis; they are not standards values. Twenty items: thirteen furniture, seven sanitary. Refusals: a family other than furniture/sanitary and a lang other than en/tr, each with the list.

arch_catalogue_insertA

Define the item's block ARCH_ once, insert it on the furniture or sanitary layer.

The block carries an invisible ITEM attribute with the catalogue name. Its size is a nominal catalogue dimension (reported with size_basis), not a standards value; the outline is a plan symbol drawn inside that footprint. The furniture / sanitary layer is created from the arch layer set when the drawing lacks it. Refusals, all before any write: an unknown name (with the nearest catalogue names) and a non-finite coordinate or rotation.

arch_gridA

Axis lines on the arch grid layer (its CENTER linetype comes from the layer) and a 5 mm bubble with its label at both ends of each axis, on the symbol layer.

Numbers run along x and letters along y (A..Z, then AA, AB - no letter is skipped) unless labels names them. The bubble and label sizes are this server's declared drafting sizes in paper millimetres, not a standards value. Refusals, all before any write: an empty axis list in either direction, a non-finite or duplicate position, a label list whose length does not match its positions, a duplicate or empty label, an unknown labels key, and a non-positive extension or scale.

arch_symbolA

Draw one architectural symbol on the arch symbol layer.

Sizes are this server's declared drafting sizes in paper millimetres times scale (a 16 mm north-arrow circle, 10 mm section and elevation bubbles), not standards values. Refusals, all before any write: an unknown kind (with the list), a parameter the kind does not take (with the ones it does), a section mark without p1/p2, with an empty label, an unknown side or a cut line too short for its two arrows, an elevation direction outside up/right/down/left or named twice, a non-finite level value, and a lang other than en/tr.

arch_plan_from_specA

A whole plan drawn inside one transaction: walls with their hosted doors and windows, stairs, room labels whose areas are measured off the walls just drawn, the exterior dimension chains and the door / window / room schedules.

Every item is validated before the transaction opens, so a refusal leaves the drawing untouched and names its path (walls[1].thickness: ..., rooms[0].area: ...). What only the drawing can refuse - a room point in no closed face - rolls the transaction back, and so does a cancelled request (the rollback runs under an anyio shield). The result carries each step's own result, the wall engine's omitted list and the three arch_* critique focuses run over the committed plan.

Refused by name: an unknown key, no walls, an unknown language or material, a non-finite or non-positive number, an arc segment in a wall axis, an opening that overlaps another or runs past its wall segment (both ids named), a typed room area (areas are measured, never typed), an unknown chain side or schedule kind, and a transaction that cannot be opened. Catalogue furniture, the grid and symbols are separate tools (arch_catalogue_insert, arch_grid, arch_symbol).

drawing_understandA

One report on a drawing somebody else made, every claim with its evidence and a confidence. Never modifies the drawing: a file is read as it is, and the current document through a snapshot (headless: the document in memory; live: a Document.Export DXF copy in a temporary folder, deleted after). An xref's own entities are not read - the host drawing is.

  • units: $INSUNITS as declared against the unit the geometry implies (text heights, wall thickness, door swings, labelled room areas, overall size - each item with its median and its value under every candidate unit). A disagreement is a warning with the numbers, never a silent correction.

  • extents: declared, computed and robust boxes and the outliers that stretch them, farthest first, by handle.

  • clusters: separate bodies of model-space content (plan copies, sheets, details), each with its box, entity count, commonest layers and tallest labels.

  • layers: entity count, drawn length (and metres in the inferred unit) and the discipline / service each most likely carries - the vocabulary's confidence (0.9) for a name keyword, 0.6 when most texts on the layer agree, 0.4 when fewer do.

  • equipment_tags (a tag found more than once is ambiguous), rooms (room labels in five languages, each with the wall-layer face it sits in and its measured area), languages (Latin / Turkish / Cyrillic character classes), blocks (named / anonymous, kinds by name), layouts, title_block and warnings.

Refused before anything is read: a path that does not exist, a DXF over MAX_DXF_BYTES (the refusal names the size and the variable), and a file the engine cannot parse (a DWG headlessly: ezdxf reads DXF only).

drawing_scale_checkA

Is the drawing to scale against the reference - or a schematic whose lengths are lengths of drawn line, not of pipe? Read-only on both drawings.

Equipment tags are matched between the two (a Cyrillic look-alike such as Т4100 is the Latin T4100). Only a tag found exactly once in each is used; a tag found more than once (plan copies, a legend, a second sheet) is listed in ambiguous and takes no part. When a drawing holds several bodies of content (two copies of one plan), the pair of scopes - whole drawing or one cluster on each side - that matches the most tags is used and named in scope. For every two matched tags at least min_pair_mm apart on the reference, the ratio of their distances is taken (both in millimetres by each drawing's inferred unit, see drawing_understand). The result gives the matched tags, the median ratio, the quartiles and their range, the share of pairs within +/-10 % of the median, the same per room of the reference (or per cluster for tags in no room) in groups, and a verdict: to_scale (at least 80 % within the band; factor is the median, so a uniform other scale is recognised), schematic (50 % or less), partly in between, insufficient with fewer than three matched tags or no pair above the floor. Tag labels are not equipment centres; the band and the floor absorb that offset, and the result's notes say so.

Refused before anything is read: a reference or path that does not exist, a DXF over MAX_DXF_BYTES (the refusal names the size and the variable), a file the engine cannot parse (a DWG headlessly), and a min_pair_mm that is not a positive finite number.

drawing_diffA

Compare two revisions of one drawing by geometric signature (spec §10).

Entities are matched exactly first (type, layer, geometry rounded to tol, text, block, attributes - handles do not matter), then by handle while handles look stable, then by type + layer + nearest position within move_tol; what is left is added or removed. The report counts changes by layer and type, lists each changed entity with what changed (moved by, text from -> to, attribute from -> to, radius from -> to, ...), compares the block definitions when both revisions are DXF files or the headless current document, and groups the changes into clusters.

Read-only unless markup=True: then revision clouds are drawn around the model-space clusters on the current document, which must be the newer revision, and filed as one revision row - the only write this tool makes.

Refused before anything is read: markup=True with new_path (the clouds go on the current document), markup=True without a valid rev, markup=True on an engine without the revcloud capability (the live engine - capability: "revcloud"), a path that does not exist, a DXF over MAX_DXF_BYTES (the size and the variable named), a file that is not a readable DXF, and a non-positive tol or move_tol.

drawing_topology_checkA

Topology of a line network (spec §11): dangling ends, near misses (end to end and end to line within gap) and interior crossings (two lines of one layer crossing away from their ends). Never modifies the drawing.

An end that touches another network line, any curve on another layer (a tank outline) or the box of any block reference (a valve, a pump) is connected. Arcs and bulged polyline segments are measured as true arcs; arcs are not tested for crossings. The default layers come with their classification as evidence.

Refused before any work: a path that does not exist or cannot be read, a layers entry that is not a layer of the drawing (the drawing's layers named), no layer classified as a network layer when layers is omitted (name them), a non-positive tol or gap, and a gap that does not exceed tol.

pipe_takeoffA

A pipe takeoff: topology from the P&ID, lengths from the layout, rows by room x service x diameter.

The P&ID gives the runs (junctions merged, tees split, a line drawn twice counted once, valves and reducers bridged), each run's service (the layer, overridden by a supply / return word near the line), its diameters exactly as labelled (direct, carried by continuity - never across a reducer - or unassigned) and the equipment tags at its ends. The length comes from the layout unless the scale check calls the P&ID to scale: the rectilinear minimum spanning tree of the run's tag positions on the layout, each connection along x first then y, plus vertical_allowance per connection. The P&ID's drawn length stays beside it as schematic_m, never as the answer. Lengths are metres from the unit the geometry implies; an INSUNITS that disagrees is a warning, never a factor. Status A / B / C per run: a C run (an end on no equipment, a tag missing from or written twice on the layout) is on the Kontrol sheet with its schematic length, counted in the total and flagged.

Read-only on both drawings. With output it writes one workbook - Metraj, Özet, Kontrol, Metodoloji - as XLSX and, always, as CSV beside it.

Refused before a drawing is read: lang outside tr / en / ru, an unknown service or length source, an allowance outside 0-1, a negative vertical allowance, a non-positive tolerance, and length_source='layout' without a layout. A missing, unreadable or oversize drawing is refused by the reader, which names MAX_DXF_BYTES. Refused after the scale check: length_source='pid' on a P&ID it calls schematic, unless force=True (the refusal quotes the statistics). Without openpyxl the XLSX is not written and files.refused carries capability: "xlsx_write" naming the office extra; the CSV files are written all the same.

cable_takeoffA

A cable takeoff: one row per electrical load, the shop's cable method made repeatable.

Power, phases, voltage, neutral and VFD come from the P&ID's electrical texts near each tag (Russian, Turkish and English spellings). Power is never invented: a load with no stated kW keeps an empty cell and an open item. The panel comes from the layout's wiring callouts ('Wiring to CP1' and its variants, normalised to CP-1), else from the P&ID ('к CP1'); a load neither places takes the nearest panel on the layout, flagged panel_inferred (panel_rule='stated' leaves it open). The length is the Manhattan distance on the layout from the load's tag to its panel's tag, and the cable is ROUNDUP(length x (1 + allowance)) to the metre. Room and panel totals count known power once: a load wired to a panel that states its own power is part of that package, and the package's power is counted instead of its children's - the rule is written on the method sheet. Sections only from section_rules; no standard table is applied. Open items: missing power, missing panel, a tag or panel not on the layout, no layout at all, a load no section rule covers.

Read-only on both drawings. With output it writes one workbook - Metraj, Özet, Kontrol, Metodoloji - as XLSX and, always, as CSV beside it.

Refused before a drawing is read: lang outside tr / en / ru, an allowance outside 0-1 and a malformed section rule (named by its path, section_rules[0].section: ...). A missing, unreadable or oversize drawing is refused by the reader, which names MAX_DXF_BYTES. Without openpyxl the XLSX is not written and files.refused carries capability: "xlsx_write" naming the office extra; the CSV files are written all the same.

Prompts

Interactive templates invoked by user choice

NameDescription
prompt_floor_planGenerate a prompt for creating a floor plan drawing.
prompt_pid_diagramGenerate a prompt for creating a P&ID (Piping and Instrumentation Diagram).
prompt_electrical_schematicGenerate a prompt for creating an electrical schematic diagram.
prompt_mechanical_drawingGenerate a prompt for creating a mechanical engineering drawing.
prompt_quick_drawingGenerate step-by-step instructions for creating a drawing from a description.

Resources

Contextual data attached and managed by the client

NameDescription
Current Drawing InfoMetadata for the currently open drawing
Layer ListAll layers in the current drawing with properties
Block LibraryAll block definitions in the current drawing
Entity StatisticsEntity counts by type and layer
Server StatusAutoCAD MCP Pro server and backend status
P&ID Symbol CatalogueEvery P&ID symbol pid_symbol_insert can place: families, variants, ports, parameters
ISA-5.1 Identification LettersISA-5.1-2009 Table 4.1 letter tables, the tag grammar and its disambiguation rules

TDQS

B3.1/5.0

Scored across 242 tools

Disambiguation3/5

With 242 tools, many share domains and some explicitly overlap (e.g., block_insert vs entity_create_block_ref, drawing_save vs drawing_save_as vs drawing_export_dwg). While descriptions are thorough, the sheer volume makes misselection likely, though most tools are conceptually distinct.

Naming Consistency3/5

Tool names are predominantly snake_case with domain prefixes (entity_, layer_, drawing_), but verb placement varies (entity_create_line vs layer_unlock) and a few lack a domain prefix (cad_batch, point_from_snap). Still readable, but not fully consistent.

Tool Count1/5

242 tools is an extreme mismatch for any server's purpose; even a comprehensive CAD suite would rarely need this many. This forces agents to navigate an unwieldy surface and increases cognitive load.

Completeness4/5

The surface is remarkably comprehensive across entity types, layers, blocks, dimensions, layouts, and specialized domains (mechanical, architectural, P&ID), with few obvious gaps. Minor gaps exist (e.g., layer rename) but are workaround-able.

Maintenance

ActivityNo data
ResponsivenessWithin a week