Skip to main content
Glama
xuantinhnbs-rgb

Autodesk Civil 3D MCP Server

civil3d-mcp

English · Tiếng Việt

CI License: MIT Python Platform

An MCP server that drives Autodesk Civil 3D over COM. It lets Claude — or any MCP client such as Claude Code, Claude Desktop, Cursor or Cline — build TIN surface → alignment → profile → corridor → cross sections → deviation statistics from filtered point-cloud data, and export the numbers straight to CSV.

It was written for as-built BIM research on transport infrastructure, where the deliverable is a table of deviations with a defensible provenance, not a picture.

filtered point cloud            civil3d-mcp                         report
────────────────────            ───────────                         ──────
LAS/LAZ ──filter──> XYZ  ──> TIN surface ──┬─> volume surface ──> cut/fill quantities
                                           ├─> alignment ─> profile ─> station/elevation CSV
                                           ├─> corridor ─> sample lines ─> cross-section CSV
                                           └─> check points ──> RMSE, standard deviation

The point-cloud filtering step is out of scope here. A separate MCP server covers it: recap-mcp reads Autodesk ReCap projects and analyses LAS/LAZ. The two repositories are independent — either is useful on its own.

Every tool returns JSON with an ok key — {"ok": true, ...} on success, {"ok": false, "error": "..."} on failure. No tool lets an exception escape, so the model receives a readable message instead of a raw COM stack trace.

Note on documentation language. Code comments and the detailed guide are written in Vietnamese. This README is the English entry point; the Vietnamese one is README.vi.md.


What it looks like

A TIN surface built entirely through MCP calls

A TIN surface and profile built in Civil 3D through the MCP server

No project file was opened: a new drawing from the Civil 3D template, then create_tin_surface and add_points_to_surface to load the points, and create_alignment, create_profile_from_surface and create_profile_view for the rest. The full call sequence is in docs/images/README.md.

Verified on a machine with Civil 3D closed

install.py --check, ruff and pytest all passing

install.py --check loads the server, counts its tools and reports which Civil 3D it found; ruff is clean; the offline suite passes — with no Civil 3D session open.


Related MCP server: Civil3D MCP Server

Requirements

  • Windows. Civil 3D's COM API is Windows-only.

  • Python 3.10 or newer, with pywin32 and mcp.

  • Autodesk Civil 3D. Civil 3D runs on top of AutoCAD, but plain AutoCAD is not a substitute: the Surfaces/Alignments/Corridors collections only exist in Civil 3D. check_civil3d_connection detects that case and says so explicitly.

The offline test suite runs on a machine without Civil 3D installed.

Verified environment

Component

Value on the development machine

Civil 3D

2026 (English), C:\Program Files\Autodesk\AutoCAD 2026\

COM version

13.8 (AeccXUiLand.AeccApplication.13.8)

Underlying AutoCAD

AutoCAD.Application.25.1

Python

3.14, with pywin32 and mcp

The COM version number does not track the release year. The server discovers it from the registry rather than hardcoding it, so it keeps working when you upgrade — but the API signatures were measured against 13.8, so another version needs re-testing.


Install

git clone https://github.com/xuantinhnbs-rgb/civil3d-mcp.git
cd civil3d-mcp

pip install -r requirements.txt
python install.py

install.py detects the Python interpreter and repository directory on the machine it is running on, verifies the packages, loads the server to confirm its tools register, reports which Civil 3D installation and COM version it found, and only then writes .mcp.json. You never edit a path by hand.

python install.py --check            # verify only, write nothing
python install.py --claude-desktop   # also write Claude Desktop's config

Then open Claude Code in the repository root and run /mcp to confirm the server connected.

.mcp.json is deliberately not in the repository: it contains absolute paths valid on exactly one machine. See .mcp.json.example.

Civil 3D does not need to be running at install time — the server attaches to a session lazily.


Architecture

Civil 3D runs on top of AutoCAD: the process is still acad.exe, and the automation API comes in two layers stacked on each other.

Layer

Obtained with

Gives you

AutoCAD

GetActiveObject("AutoCAD.Application.25.1")

ModelSpace, Layers, SendCommand, handles

Civil 3D – land

acad.GetInterfaceObject("AeccXUiLand.AeccApplication.13.8")

Surfaces, Alignments, Profiles, Points, Sites

Civil 3D – roadway

acad.GetInterfaceObject("AeccXUiRoadway.AeccRoadwayApplication.13.8")

Corridors, Assemblies, Subassemblies

File

Role

civil3d_mcp/com.py

The dedicated COM thread, HRESULT translation, registry version discovery, connection

civil3d_mcp/client.py

Civil3DClient: holds the connection, retries, document access, VARIANT packing

civil3d_mcp/geometry.py

Pure-Python computation: batching, station series, RMSE statistics, CSV

civil3d_mcp/surfaces.py

TIN surfaces, volume surfaces, point loading, sampling, comparison

civil3d_mcp/alignments.py

Alignments, profiles, profile views, station ↔ coordinate conversion

civil3d_mcp/corridors.py

Corridors, baselines, sample lines, cross sections

civil3d_mcp/research.py

Report deliverables: deviation grids, CSV, Markdown reports

civil3d_mcp/server.py

The MCP tool surface

Three design decisions worth knowing

One single COM thread. The MCP server runs tools in a thread pool, and COM does not allow interface pointers across threads. Every call — including the connection check and plain document property reads — goes through Civil3DClient.run(). Missing one entry point produces no error at that line; it makes a failure appear later, somewhere unrelated.

Writes verify themselves. A COM call that does not raise is not evidence the operation took effect. Every writing tool reads the result back and returns verified and verified_by. add_points_to_surface, for example, reports points_added_measured computed from the before/after difference in Statistics.NumberOfPoints — not the number of points it sent.

The first batch is a calibration. AddPointMultiple takes a SAFEARRAY whose layout the documentation does not pin down, and the wrong layout silently adds nothing. So the first batch goes out in the flat layout and is then measured; if the count did not rise, the server switches to array-of-arrays. The array_layout_used key in the result says which one worked.


Tools (58)

Connection and drawings

Tool

What it does

check_civil3d_connection

Call this first. Distinguishes: not installed / not running / attached to plain AutoCAD by mistake

launch_civil3d

Starts it with the right /ld AecBase.dbx /p <<C3D_Metric>> /product C3D arguments

create_new_drawing

New drawing from a template — the correct way to start (opening a .dwt directly edits your template). template_path must be a full path; see the note below

get_drawing_info, list_open_drawings, open_drawing, save_drawing, switch_drawing

Drawing management

send_civil3d_command

Escape hatch for what COM does not expose. Asynchronous, returns no result

get_environment_report

A software-version record for the "experimental environment" section of a paper

Surfaces

Tool

What it does

list_surfaces, get_surface_info

Listing, statistics, bounds, definition components

create_tin_surface

An empty TIN surface

add_points_to_surface

Load points over COM — for a few thousand points

add_point_file_to_surface

Attach a point file on disk — use this for real scan data

build_surface_from_xyz_file

One step: create + load + set max_triangle_length + rebuild

import_surface_file

LandXML / TIN / DEM

set_surface_build_options, rebuild_surface, delete_surface

TIN build parameters, rebuild, delete (needs confirm=True)

create_volume_surface

Compare two surfaces → cut/fill/net quantities

sample_surface_elevations, sample_surface_section

Elevation at points; a section along a line

compare_surface_to_check_points

RMSE against independently surveyed check points

compare_two_surfaces

Elevation deviation grid over the overlapping region

Alignments and profiles

Tool

What it does

list_alignments, get_alignment_info

Finds both siteless alignments and alignments inside Sites

create_alignment, create_alignment_from_polyline

From a vertex list or from a polyline

alignment_station_offset, alignment_point_location, sample_alignment

Station ↔ coordinate conversion

list_profiles, create_profile_from_surface, sample_profile

Profiles from a surface; station/elevation/grade tables

compare_profiles

As-built vs design elevation deviation by station

create_profile_view

The profile view frame

Corridors and cross sections

Tool

What it does

list_assemblies, list_corridors, get_corridor_info

Listing, baselines, station ranges, corridor surfaces

list_assembly_library, import_assembly

How to get an assembly when COM cannot create one: copy it from Civil 3D's sample assembly library

create_corridor, add_corridor_baseline, rebuild_corridor

Build and compute a corridor

sample_corridor_surface

Corridor surface elevations

corridor_points, corridor_shape_areas

Computed corridor geometry: coded points, per-layer areas

create_sample_lines, list_sample_line_groups, create_sections, read_sections

Sample lines, their groups, and cross sections

Exporting data

Tool

What it does

export_surface_comparison

Grid CSV + statistics CSV + a Markdown report recording the conditions the numbers came from

export_profile_csv, export_sections_csv

Profiles and cross sections to CSV

export_check_point_report

Check-point comparison, CSV with RMSE

export_corridor_points_csv

Corridor geometry points to CSV

export_corridor_quantities

Area by station plus volume per structural layer

A note on create_new_drawing

template_path takes a full path, not a filename:

C:\Users\<you>\AppData\Local\Autodesk\C3D 2026\enu\Template\_Autodesk Civil 3D (Metric) NCS.dwt

Pass a bare filename and Civil 3D quietly falls back to its default template. That drawing has exactly one surface style, Standard, which displays nothing — so the symptom is a surface that builds successfully, reports the right statistics, and is invisible on screen. No error is raised anywhere.

The template key in the result echoes the path that was used, so null there means no template was applied — check it rather than assuming.

Style names must also exist in the drawing. A style that is not there makes AddTinSurface fail with E_INVALIDARG, the same code as a missing BaseLayer, so the error message does not point at the real cause. The Metric NCS template ships 14 surface styles; Contours and Triangles is the clearest for a figure.


Known limits

These are properties of Civil 3D's COM API, not gaps this server could patch:

  1. Assemblies and subassemblies cannot be created from scratch. AeccAssemblies exposes only Count and Item — checked against the type library, not guessed. But they can be copied: import_assembly inserts a drawing containing an assembly and the assembly comes with it. Civil 3D ships 16 sample assembly drawings in C:\ProgramData\Autodesk\C3D 2026\enu\Assemblies\Metric\ (see list_assembly_library), so in practice this is no longer a blocker.

  2. Corridor targets cannot be assigned. AeccBaselineRegion has no target members, so any subassembly needing a target surface (all daylight / side-slope types) makes Rebuild fail with 0x80004005. Two ways forward: pick an assembly without daylight subassemblies, or delete that subassembly after import (subassembly.Delete() does work over COM).

  3. Corridor surfaces cannot be created. AeccCorridorSurfaces is read-only too. Use corridor_points / corridor_shape_areas instead: they read the computed corridor geometry directly, which is enough for a station/offset/elevation table and for per-layer quantities.

  4. Subassembly parameters cannot be edited. ParamsDouble/ParamsLong/… return a COM object on which neither Count nor Item resolves, and CastTo with a makepy'd type library still reports "Element not found". Lane width, cross slope and the like must be changed in Civil 3D's properties panel.

  5. send_civil3d_command is one-way. COM returns when the command is queued; no error code comes back, and any command that waits for a mouse click will hang the UI. Verify with a reading tool after every command.

  6. The drawing must come from a Civil 3D template. Creating a surface, alignment or profile requires a style that exists; a blank AutoCAD drawing has none, and the tool reports that clearly.

  7. LandXML cannot be exported over COM (import only). Export goes through send_civil3d_command with -LandXMLOut, verified by checking the file on disk.

  8. Large corridors take a long time to rebuild and COM blocks until finished. Read the out_of_date key: still true means the computation has not finished.

  9. Units follow the drawing. The server does not convert. get_drawing_info returns measurement and drawing_units so you can check before reading numbers.

  10. Volume signs follow Civil 3D's convention: cut is where the comparison surface is below the base surface. create_volume_surface states the convention in its result.


Where COM differs from its documentation

The 16 differences listed in README.vi.md were measured on Civil 3D 2026 (COM 13.8), not inferred: each is a call that was refused, or returned nothing, until it was made the way the right-hand column describes. They are all handled in this server; they are listed so that nobody reading the code thinks those lines are redundant, and so the next person writing a Civil 3D tool loses less time.

A few highlights:

  • Surfaces.AddTinSurface demands both Layer and BaseLayer; omitting BaseLayer surfaces as a generic "Exception occurred".

  • Profiles.AddFromSurface wants the surface name as a string, while SampleLineGroups.Add wants a style object — the opposite convention, in the same API.

  • Surfaces.Item(i) hands back the base IAeccSurface interface, with no Statistics. The object returned by AddTinSurface at creation time carries the derived interface, so the same line of code works right after creating a surface and fails when the drawing is reopened in a later session.

  • AeccRoadwayDocument.Assemblies refuses the property itself with E_INVALIDARG when the drawing has no assemblies, so "none yet" looks exactly like "the call is broken".

The full table, with all 16 rows and three further behavioural notes, is in the Vietnamese README. A test asserts that the count stated in prose matches the number of rows in the table — that sentence had already drifted once.


Development

pip install -r requirements-dev.txt

ruff check .                 # lint
pytest                       # offline suite; no Civil 3D needed
python install.py --check    # loads the server, prints tool count and Civil 3D version

# Live suite: builds real geometry in a running Civil 3D
$env:CIVIL3D_LIVE_TEST=1; pytest tests/test_live_civil3d.py

The first three are exactly what CI runs.

The offline suite runs on a machine without Civil 3D — which is why CI can run it at all. It uses a fake COM layer to exercise the paths a real machine rarely reaches:

  • a COM call that "succeeds" without taking effect (creating a surface that does not appear, loading points that do not arrive);

  • a wrong array layout being silently ignored, and the calibration step catching it;

  • regressions for differences #1, #2 and #6 in the table — removing the BaseLayer assignment or dropping coordinates to 2D turns those tests red;

  • two non-overlapping surfaces (the signature of mismatched coordinate systems) producing an error that names the cause;

  • "busy" being distinguishable from "not running";

  • deviation statistics: RMSE about zero differs from standard deviation about the mean when there is a bias.

The computation in geometry.py is tested against hand-computable values (a 3-4-5 triangle, the RMSE of a symmetric series, the area of a square), never against reference values copied from a previous run.

The live suite (CIVIL3D_LIVE_TEST=1) builds two parallel planes exactly 0.05 m apart over 100 × 40 m, then requires Civil 3D to return the analytic answer:

Quantity

By hand

Civil 3D returns

RMSE against check points

0.050 m

0.050 m

Standard deviation (constant offset)

0

0

Fill volume

100 × 40 × 0.05 = 200 m³

200.000 m³

Longitudinal grade on the section

0.020

0.020

Profile elevation at Km0+000 / +100

10.00 / 12.00 m

10.00 / 12.00 m

"It ran without an error" is not the criterion: every step has to produce the right number. This suite is what found all 16 API differences above.

See CONTRIBUTING.md for conventions and the checklist for adding a tool, and CHANGELOG.md for what changed between versions.


Troubleshooting

Symptom

Fix

/mcp shows the server as not connected

Run python install.py --check

ModuleNotFoundError: mcp or win32com

pip install -r requirements.txt

Every tool says no session is running

Open Civil 3D, or call launch_civil3d (1–3 minutes)

Tools report being attached to plain AutoCAD

Plain AutoCAD cannot serve these tools — start Civil 3D itself

Creating a surface fails complaining about styles

The drawing is not from a Civil 3D template. Use create_new_drawing

Rebuild fails with 0x80004005

The assembly has a daylight subassembly and corridor targets cannot be set over COM — see limit 2

A comparison reports deviations of hundreds of metres

Mismatched coordinate systems; the error names the axis

Garbled output running scripts by hand

Set PYTHONIOENCODING=utf-8 first


Security

This server hands a model direct control of the open drawing: it can delete surfaces, save over files, and send arbitrary AutoCAD commands. Read SECURITY.md before connecting it, and report vulnerabilities privately rather than in a public issue.


License

MIT — free for any use including commercial, keep the copyright notice.

Contributions are welcome in English or Vietnamese — see CONTRIBUTING.md and CODE_OF_CONDUCT.md.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Connects Claude to a running Autodesk Civil 3D instance via COM automation to perform drawing, surface, alignment, COGO point, line, and corridor operations.
    7
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    Enables AI assistants to interact with Autodesk Civil 3D through natural language, supporting tools for surfaces, alignments, profiles, corridors, pipe networks, COGO points, and AutoCAD geometry.
    9
    3
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Lets any MCP-compatible AI assistant read and edit Autodesk Civil 3D drawings through tools for alignments, surfaces, corridors, pipe networks, quantity takeoff, and cut/fill, using a local bridge plugin and named pipes.
    MIT