Can an agent draw CAD(Computer-Aided Design) drawings with MCP?
What is CAD (Computer-Aided Drawing)?
CAD, or Computer-Aided Drawing (often more broadly referred to as Computer-Aided Design), is the use of computer systems to assist in the creation, modification, analysis, or optimization of a design. CAD software is used to increase the productivity of the designer, improve the quality of design, improve communications through documentation, and to create a database for manufacturing. CAD outputs often come in the form of electronic files for print, machining, or other manufacturing operations. It is widely used in many industries, including architecture, engineering, construction, manufacturing, and product design, allowing for the creation of precise 2D drawings and 3D models.
What is MCP (Model Context Protocol)?
MCP stands for Model Context Protocol, and it is a system-level protocol introduced by OpenAI to manage how context is structured, passed, and interpreted by AI models like GPT-4 and beyond.
It’s essentially the standard that defines how the model interacts with various tools, memory, and user instructions in a structured, modular way — all within a “context.”
CAD MCP
import os
from draw_2d import draw_line, draw_circle, draw_arc
from fastmcp import FastMCP
import FreeCAD as App
import importDXF
mcp = FastMCP("cad")
doc = None
@mcp.tool()
def draw_2d_shapes(shapes: list[dict]) -> str:
"""
Draw 2D shapes (lines, arcs, circles) using FreeCAD
Args:
shapes: List of shape definitions, each with type and parameters:
- type: 'line', 'arc', or 'circle'
- For line: points: [[start_x, start_y], [end_x, end_y]]
- For arc: start_point: [x, y], end_point: [x, y], center_point: [x, y]
- For circle: center: [x, y], radius: float
"""
global doc
try:
# Create a document if none exists
if not App.ActiveDocument and not doc:
doc = App.newDocument()
doc = App.ActiveDocument
# Process each shape
for i, shape in enumerate(shapes):
shape_type = shape.get('type')
if shape_type == 'line':
points = shape.get('points')
if not points or len(points) != 2:
raise ValueError(f"Invalid points for line {i}")
shape_obj = draw_line(points[0], points[1])
doc.addObject("Part::Feature", f"Line{i}").Shape = shape_obj
elif shape_type == 'arc':
start_point = shape.get('start_point')
end_point = shape.get('end_point')
center_point = shape.get('center_point')
if not all([start_point, end_point, center_point]):
raise ValueError(f"Invalid points for arc {i}")
shape_obj = draw_arc(start_point, end_point, center_point)
doc.addObject("Part::Feature", f"Arc{i}").Shape = shape_obj
elif shape_type == 'circle':
center = shape.get('center')
radius = shape.get('radius')
if not all([center, radius]):
raise ValueError(f"Invalid parameters for circle {i}")
shape_obj = draw_circle(center, radius)
doc.addObject("Part::Feature", f"Circle{i}").Shape = shape_obj
else:
raise ValueError(f"Unknown shape type: {shape_type}")
# Export to DXF
dwg_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "2d_lines.dxf")
importDXF.export(doc.Objects, dwg_path)
doc = None
return "2d_lines.dxf"
except Exception as e:
print(f"Error drawing lines: {e}")
raise
if __name__ == "__main__":
mcp.run(transport="stdio")
MCP Client
import asyncio
from dotenv import load_dotenv
from langchain_mcp_adapters.tools import load_mcp_tools
from langchain_openai import ChatOpenAI
from langchain_google_genai import ChatGoogleGenerativeAI
from langgraph.prebuilt import create_react_agent
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
load_dotenv()
# model = ChatOpenAI(model="gpt-4o")
model = ChatGoogleGenerativeAI(model="gemini-2.0-flash")
# Configure server parameters
# This will connect to the MCP server running in the same directory
server_params = StdioServerParameters(
command="FreeCAD\\bin\\python.exe",
args=["mcp_server.py"],
)
async def main():
"""
Main async function that:
1. Connects to the MCP server
2. Loads available tools from the server
3. Creates an agent with the loaded tools
4. Performs stock analysis using the agent
"""
async with stdio_client(server_params) as (read, write):
# Create a client session with the server
async with ClientSession(read, write) as session:
# Initialize the session with the server
await session.initialize()
# Load available tools from the server
tools = await load_mcp_tools(session)
# Create a reactive agent using the loaded tools
agent = create_react_agent(model, tools)
# -- korean
# agent_response = await agent.ainvoke({"messages": "10mm 크기의 삼각형을 그려줘. 설명은 필요없어."})
# agent_response = await agent.ainvoke({"messages": "하트 모양을 자연스럽게 그려줘. 설명은 필요없어."})
# agent_response = await agent.ainvoke({"messages": "별 모양을 그려줘. 설명은 필요없어."})
# -- english
# agent_response = await agent.ainvoke({"messages": "Draw a heart shape. Don't need explanation."})
# agent_response = await agent.ainvoke({"messages": "Draw a star shape. Don't need explanation."})
print(agent_response)
if __name__ == "__main__":
# Run the async main function
asyncio.run(main())
Results
Korean Prompt
- Model: ChatGPT-4o
10mm 크기의 삼각형을 그려줘. 설명은 필요없어.
하트 모양을 자연스럽게 그려줘. 설명은 필요없어.
별 모양을 그려줘. 설명은 필요없어.
- Model: Gemini-2.5-flash
10mm 크기의 삼각형을 그려줘. 설명은 필요없어.
하트 모양을 자연스럽게 그려줘. 설명은 필요없어.
별 모양을 그려줘. 설명은 필요없어.
English Prompt
- Model: Gemini-2.5-flash
Draw a heart shape. Don't need explanation.
Draw a star shape. Don't need explanation.