Automate DWG drawings with Python (and with AutoLISP or MCP)
Drawing the same structural grid in every project, counting blocks in a hundred drawings or putting on the right layer what someone left on layer 0 are tasks that repeat. LinceCAD can be driven from outside through a local API: a Python script opens drawings, creates entities, changes layers, runs commands and saves to DWG. Everything goes through channels on your own computer; nothing goes out to the internet.
Four routes, depending on what you need
| Route | What it is | When to use it |
|---|---|---|
| Local API (JSON-RPC) | One JSON message per line over a named pipe (Windows) or a socket (Linux). Works from any language. | Driving LinceCAD, with its window open or without it, from your own programs. |
Python lince client | A dependency-free library on top of that API: dib.linea(…), dib.guardar_como(…)… | Shorter, more readable Python scripts. |
lince_nucleo wheel | A compiled Python module that reads, modifies and saves DWG/DXF without opening LinceCAD. | Batches of files, servers or Jupyter. |
| AutoLISP | The built-in interpreter, with about 200 functions. | Your own commands inside the program, or LISP routines you already have. |
LinceCAD also includes an MCP server for connecting AI assistants, which we cover at the end.
Step 1: enable automation
The API is disabled by default. There are two ways to use it:
- With the window open: in
OPTIONS, Automation tab, enable the local channel. There you can also make it read-only and restrict the folders where it can open, save and plot. The channel is\\.\pipe\lince-<user>on Windows and$XDG_RUNTIME_DIR/lince.sockon Linux. - Without a window:
lince --servidorserves the API with nothing on screen, for batch processes. With--canal NAMEyou choose the name of the pipe. On Linux it needs a graphical session (orxvfb-run).
Programs identify themselves with a token (a 64-character password) stored in
api.toml, in %APPDATA%\lince on Windows or ~/.config/lince on Linux. Only
your user can read it.
Step 2: a script with the standard library
This example needs nothing installed but Python. First start lince --servidor --canal blogpy (or use
the channel of the open window). The script authenticates with the token, creates a drawing, a layer and a
30 × 20 parcel, and saves it as DWG:
import json, os
# The token (the API password) is in %APPDATA%\lince\api.toml
toml = os.path.join(os.environ["APPDATA"], "lince", "api.toml")
ficha = next(l.split("=", 1)[1].strip().strip('"')
for l in open(toml, encoding="utf-8") if l.startswith("ficha"))
canal = open(r"\\.\pipe\blogpy", "r+b", buffering=0) # lince --servidor --canal blogpy
n = 0
def llamar(metodo, **params):
global n
n += 1
msg = {"jsonrpc": "2.0", "id": n, "method": metodo, "params": params}
canal.write((json.dumps(msg) + "\n").encode("utf-8"))
r = json.loads(canal.readline())
if "error" in r:
raise RuntimeError(r["error"]["message"])
return r["result"]
llamar("session.hello", token=ficha)
llamar("document.new")
llamar("layer.create", name="PARCELA", color=1)
llamar("entity.create", entity={"type": "LWPOLYLINE", "layer": "PARCELA", "closed": True,
"vertices": [[0, 0], [30, 0], [30, 20], [0, 20]]})
print(llamar("document.summary")["byType"]) # {'LWPOLYLINE': 1}
print(llamar("document.saveAs", path=r"C:\planos\parcela.dwg"))
The first request on each connection must be session.hello; otherwise the connection is closed. On
Linux, instead of open(), connect a socket.AF_UNIX to the socket path and use
s.makefile("rwb", buffering=0); the rest is the same.
The API has methods for drawings (document.open, save, saveAs,
summary…), entities (entity.query, get, create,
set, delete, as objects or as entget DXF lists), layers, blocks, styles,
variables, selection, undo, commands (command.run), AutoLISP (lisp.eval), plotting to
PDF, PNG and SVG, view capture and events. document.saveAs saves to DWG or DXF depending on the
extension, in version 2018 by default or in 2013, 2010, 2007, 2004, 2000 and R14.
Step 3: the same with the Python client
The lince client wraps that API in objects. This script, with lince.iniciar(), starts
LinceCAD without a window, draws a structural grid with its labels and twelve 30 × 30 cm columns, and saves the
DWG, a PDF and an image:
import lince
ejes_x = [0, 5.0, 10.5, 16.0] # grid line positions, in meters
ejes_y = [0, 4.5, 9.0]
h = 0.15 # half the side of a 30 x 30 cm column
with lince.iniciar() as s: # starts LinceCAD without a window
dib = s.nuevo()
dib.crear_capa("EJES", color=1)
dib.crear_capa("PILARES", color=7)
dib.crear_capa("ROTULOS", color=3)
with dib.transaccion(): # everything is a single undo step
for i, x in enumerate(ejes_x):
dib.linea([x, -1.5], [x, ejes_y[-1] + 1.5], layer="EJES")
dib.texto([x - 0.15, ejes_y[-1] + 2], str(i + 1), altura=0.4, layer="ROTULOS")
for j, y in enumerate(ejes_y):
dib.linea([-1.5, y], [ejes_x[-1] + 1.5, y], layer="EJES")
dib.texto([-2.3, y - 0.2], "ABC"[j], altura=0.4, layer="ROTULOS")
for x in ejes_x:
for y in ejes_y:
dib.polilinea([[x - h, y - h], [x + h, y - h], [x + h, y + h], [x - h, y + h]],
cerrada=True, layer="PILARES")
print(dib.resumen()["byType"]) # {'LINE': 7, 'LWPOLYLINE': 12, 'TEXT': 7}
dib.trazar_pdf(r"C:\planos\ejes.pdf")
dib.guardar_como(r"C:\planos\ejes.dwg")
dib.captura(r"C:\planos\ejes.png", ancho=1280)

dib.captura.To work with the window already open, use lince.conectar() and s.dibujo (the active
drawing). There are also .circulo, .arco, .mtexto, .insertar
(blocks), .consultar (by type, layer, box or filter), .comando, .lisp and
.trazar_png/.trazar_svg.
Without opening LinceCAD: the lince_nucleo wheel
To process many files, the lince_nucleo wheel works inside the Python process itself. This snippet,
from the documentation, lists the circles in a drawing and saves it as DWG 2018:
import lince_nucleo as ln
dib = ln.abrir("plano.dwg")
for e in dib.consultar(tipo="CIRCLE"):
print(e["handle"], e["radius"])
dib.guardar("salida.dwg", "2018")
The alternative without Python: AutoLISP
If you already work with LISP, you can keep doing so. The LinceCAD interpreter supports defun C:,
ssget with filters, entget, entmod, entmake and
command, among others; routines are loaded with APPLOAD or automatically from
acaddoc.lsp. This command counts the columns in the previous drawing:
(defun C:CONTARPILARES (/ ss) (setq ss (ssget "X" '((0 . "LWPOLYLINE") (8 . "PILARES")))) (princ (strcat "\nPilares: " (itoa (if ss (sslength ss) 0)))) (princ) )
On ejes.dwg it replies “Pilares: 12” (columns: 12). For fixed sequences of commands there are also
scripts (SCRIPT).
AI assistants with MCP
lince --mcp is an MCP (Model Context Protocol) server over standard input and output, for
assistants that launch it themselves. With the window open, you can also enable an MCP server over HTTP, only on
127.0.0.1. The assistant sees tools to open, query, create, dimension, insert blocks, plot to PDF,
capture the view and undo, and the LinceCAD help as documentation. For example, to add it to Claude Code:
claude mcp add --scope project lince -- "C:\Program Files\lince\lince.exe" --mcp
With confirmation turned on, each change the assistant asks for waits in the AIACTIONS palette until
you accept or reject it, and everything a call does is undone with a single UNDO.
Limitations
- Local only. The API serves programs on the same computer; the pipe rejects remote clients and
the HTTP server does not listen outside
127.0.0.1. - One request at a time per connection, and no JSON-RPC batches. To work in parallel, open several connections.
- Model space entities. Dimensions are read-only through
entity.create: they are created withcommand.runor with the MCP tooladd_dimension. True color is read but not written. - No prompts to the user.
lisp.evalfails if the routine asks for input (getpoint,entsel…), and windowless mode does not open dialog boxes. - The wheel does not run commands, AutoLISP, plots or captures: the client or the window does that.
- Python packages in the beta. The API and the MCP server come in
lince.exe. Thelinceandlince_nucleopackages are not yet published on PyPI or shipped with the installer (the package currently namedlinceon PyPI belongs to another project); the step 2 example works without them.
Frequently asked questions
What if the starting drawing is a scan? It first has to be turned into vectors: we explain it in how to vectorize a scanned drawing and convert it to DWG.
And on Linux? The API works the same way, with a Unix socket. Read how to open and edit DWG files on Linux.
And for surveying? The workflow with the Topography tab is in contour lines from a LAS/LAZ point cloud.
The local API, AutoLISP and the MCP server come with LinceCAD, with a perpetual license. Download · See pricing · AutoLISP, automation and all other features.