AutoCAD geometry is dumb. A circle doesn’t know if it’s a pipe, a column, or just a sketch. What if you could tell AutoCAD what it is — in plain English — and it understands?
That’s the question I set out to answer. Not with a new command or a dialog box, but with a conversation. This post walks through how I built an agentic AI app that runs inside AutoCAD, understands your domain schema, and takes real actions on the drawing — through tools you define and control.
See It First
Before the architecture, here’s what it looks like in practice. Draw a circle. Open the chat
panel (MCPCHAT). Type:
“Register this as a 6-inch carbon steel SCH40 pipe for P&ID drawing PID-001”
The AI selects the entity, writes XData with the pipe spec and material, creates an Extension Dictionary entry with the drawing reference — and confirms exactly what it stored. No form. No ribbon button. One sentence.
Then type: “Is this entity ready for ISO submission?” — and it audits every required field against the domain rules you gave it, tells you what’s missing, and offers to fill it in.
That’s the payoff. Now let’s look at how it works.
What You Will Learn
- How a natural language prompt becomes a function call inside a live AutoCAD document
- How to define tools the AI can use via the
IToolinterface - How to execute those tools safely on the AutoCAD document context thread
- How to ground the AI in your domain knowledge via the system prompt
- Where the boundary is between AI reasoning and your application logic
Prerequisites
This sample uses Anthropic’s Claude as the AI model,
called directly via the Anthropic Messages API
using HttpClient — no SDK dependency. This keeps the plugin lean and avoids assembly
version conflicts with what AutoCAD already loads. You will need your own API key (BYOK —
Bring Your Own Key). The plugin stores it encrypted on disk using Windows DPAPI and sends it
only to api.anthropic.com over HTTPS.
The Agentic Loop
A chatbot answers questions. An agentic app takes actions. The difference is the tool loop.
while (true)
{
var response = await _model.CompleteAsync(history, _tools, ct);
if (response.Kind == ModelResponseKind.Text)
{
post(response.Text);
break;
}
// Model wants to call a tool — execute it and feed the result back
var tool = _tools.First(t => t.Name == response.ToolUse.ToolName);
var result = await tool.ExecuteAsync(new ToolInput(response.ToolUse.Arguments), ct);
history.Add(ToolUse(response.ToolUse));
history.Add(ToolResult(response.ToolUse.ToolUseId, result.Content));
}
The ITool Interface
public interface ITool
{
string Name { get; }
string Description { get; }
IReadOnlyList<ToolParameter> Parameters { get; }
Task<ToolResult> ExecuteAsync(ToolInput input, CancellationToken ct = default);
}
How the Model Decides Which Tool to Call
{
"name": "acad_xdata_add",
"description": "Writes or updates XData key-value pairs on an entity under a given application name",
"input_schema": {
"type": "object",
"properties": {
"handle": { "type": "string", "description": "Entity handle (hex string)" },
"appName": { "type": "string", "description": "XData application name" },
"data": { "type": "string", "description": "Key=Value pairs separated by semicolons" }
},
"required": ["handle", "appName", "data"]
}
}
The AutoCAD-Specific Challenge
Document Context
This is where most AI tutorials break for AutoCAD.
AutoCAD enforces a strict rule: the document database can only be modified from the document
context thread. AI inference runs on a background thread. If you try to write to the database
directly from a tool’s ExecuteAsync, you get an eLockViolation.
The bridge is ExecuteInCommandContextAsync combined with a
TaskCompletionSource to carry the result back to the agent loop:
public Task<ToolResult> ExecuteAsync(ToolInput input, CancellationToken ct = default)
{
var tcs = new TaskCompletionSource<ToolResult>();
_ = AcadApp.DocumentManager.ExecuteInCommandContextAsync(_ =>
{
using var tr = db.TransactionManager.StartTransaction();
// Safe to read and write the database here
tr.Commit();
tcs.SetResult(ToolResult.Ok("Done"));
return Task.CompletedTask;
}, null);
return tcs.Task; // agent loop awaits this
}
The agent loop awaits tcs.Task. The document context thread executes the database
operation and calls tcs.SetResult when done. The loop resumes with the result
and continues the conversation. Every tool in this sample follows this pattern.
Domain Grounding via the System Prompt
The AI understands your schema because you tell it in the system prompt. Think of it as giving the model a data dictionary for your drawing — the fields that exist, the values that are valid, and the rules that apply.
This is not fine-tuning and it is not RAG (Retrieval-Augmented Generation). RAG involves dynamically retrieving relevant chunks from a large knowledge base at query time. What we are doing is simpler — the domain schema is small, static, and included in every request. Static domain grounding.
You are an AutoCAD assistant specialised in entity metadata.
XData (app = PLANT_DATA):
PipeSize — nominal pipe size: e.g. 6IN, 4IN
PipeSpec — ASME/ANSI schedule: SCH40, SCH80, STD
Material — CS (Carbon Steel), SS (Stainless Steel), PVC
Status — Draft | InReview | Approved | Superseded
Extension Dictionary (key = ENGINEERING):
DrawingRef — P&ID reference number
ApprovedBy — approver name or ID
ISOCertified — YES / NO
Replace this schema with your own and the AI adapts. No retraining. No fine-tuning. Just context.
If your domain is large — hundreds of standards documents, a live product catalog, a spec library — RAG is the natural next step. You retrieve the relevant section at query time and include it in the prompt alongside the user’s message. The tool loop stays exactly the same.
⚠️ State Integrity
Where Raw Writes Are Dangerous
Raw XData and Extension Dictionary writes are safe for metadata that your plugin owns entirely. They are not safe for data managed by a vertical product like Plant 3D or Civil 3D.
Vertical products maintain object relationship graphs. A Plant 3D pipe object
(AcPpDb3dPipeInlineAsset) has XData encoding geometry, spec, and dimensional
data — all managed by the AcPp3d API. Writing to that XData directly bypasses
the spec engine, fitting selection, and isometric extractor. The drawing looks fine.
The application model is broken.
If you are building on top of a vertical product, implement tools that call that product’s
own APIs — the ones that handle referential integrity. The ITool interface is
exactly where that boundary belongs. The AI calls your tool. Your tool calls the right API.
The object graph stays consistent.
Is This MCP?
I initially assumed I needed a full MCP server to make this work. Turns out, for AutoCAD, that’s unnecessary — and for database writes, it’s actually less safe.
MCP (Model Context Protocol) is an open standard that defines how AI models communicate with external systems over a transport layer (stdio or HTTP). It covers a full set of primitives: Tools, Resources, Prompts, Sampling, and Elicitation. This sample implements only the tool calling primitive — in-process, without any transport layer.
An out-of-process MCP server cannot call ExecuteInCommandContextAsync directly.
It would need an IPC bridge — Named Pipes, WebSockets, or a local HTTP endpoint — to hand
the operation back into the AutoCAD process. An in-process plugin skips that layer entirely.
This sample is focused on the in-process pattern: domain-specific AI intelligence embedded alongside your plugin, with direct access to the document database.
Full Demo
- “What is this entity?”
- “Register this as a 6-inch carbon steel SCH40 pipe for P&ID drawing PID-001”
- “What is this entity now?”
- “Approve it, set revision R01, approved by Madhukar”
- “Is this entity ready for ISO submission?”
What Next
- Replace raw XData tools with domain APIs
- Add workflow-specific tools
- Move to RAG if needed
- Explore Sampling and Elicitation
Source Code
https://github.com/ADN-DevTech/adn-mcp-autocad

Leave a Reply