An MCP (Model Context Protocol) server that
lets AI assistants execute CadQuery scripts and render, inspect, and export 3D
CAD models. Run it with the cadquery-mcp entry point.
For command-line workflows, use the existing cq-cli project.
-
render - Execute CadQuery code and produce shaded PNGs or SVG line drawings
- Offscreen PNG rendering preserves assembly colors and part locations
- Wires and edges render as lines alongside shaded parts
- Multiple camera angles: isometric, isometric_back, front, back, top, bottom, left, right
- Multi-view mode (isometric, front, top, right) for complex models
- Configurable image dimensions
- Hidden line rendering for SVG
-
inspect - Get geometry information about a shape
- Bounding box dimensions
- Volume and surface area
- Center of mass
- Topology counts (solids, faces, edges, vertices)
-
get_parameters - Extract customizable parameters from CadQuery scripts
-
export - Export models to various formats
- STEP, STL, SVG, DXF, AMF, 3MF, VRML, BREP
- Assembly STEP exports retain names, colors, and locations
Shapes, Workplanes with multiple objects, nested assemblies, and multiple
show_object() outputs are supported. Failed MCP tool calls set isError: true.
All tool schemas reject unrecognized arguments. Empty models return CAD errors.
Python script output from print() is sent to the server's stderr.
Use a dedicated environment with CadQuery 2.8 or later and MCP Python SDK 1.30 or later (both below their next major version). Create and activate the environment with conda:
conda create -n cadquery -c conda-forge cadquery=2.8.0 pip
conda activate cadqueryOr create it with mamba, then activate it in your conda-enabled shell:
mamba create -n cadquery -c conda-forge cadquery=2.8.0 pip
conda activate cadqueryPNG rendering requires a working VTK/OpenGL graphics backend, even when rendering
offscreen. If PNG rendering fails in your environment, request
image_format: "svg" for a line drawing that does not require a display.
The server reports PNG failures as errors and does not automatically switch formats.
git clone https://github.com/CadQuery/cadquery-contrib.git
cd cadquery-contrib/mcp-server
python -m pip install .For development (editable install):
python -m pip install -e .python -m pip install pytest
python -m pytest test_cadquery_mcp_server.py test_mcp_assemblies.py -vRegister the server from your CAD project's root, using absolute paths to the Python interpreter with CadQuery/MCP installed and to this checkout's server:
claude mcp add --transport stdio --scope project cadquery -- \
/absolute/path/to/environment/bin/python -u \
/absolute/path/to/cadquery-contrib/mcp-server/cadquery_mcp_server.pyThis writes a project-root .mcp.json (not ~/.claude/settings.json):
{
"mcpServers": {
"cadquery": {
"type": "stdio",
"command": "/absolute/path/to/environment/bin/python",
"args": ["-u", "/absolute/path/to/cadquery-contrib/mcp-server/cadquery_mcp_server.py"]
}
}
}Start or restart Claude Code in that project, approve the project server when
prompted, and check /mcp. claude mcp get cadquery shows the selected launcher,
scope, and status. A pending-approval status requires that interactive approval.
Use --scope user instead of --scope project for all projects. Local entries
take precedence over project entries, which take precedence over user entries;
remove stale registrations that shadow the intended checkout.
On WSL, run Claude Code and this Linux launcher inside WSL. A Windows-native
Claude Desktop process needs a Windows launcher or a wsl.exe wrapper instead.
If the Linux font cache is unwritable, add an env entry such as
"XDG_CACHE_HOME": "/tmp/cadquery-cache" to the server configuration.
See Claude Code's MCP documentation.
Add to your Claude Desktop configuration (~/Library/Application Support/Claude/claude_desktop_config.json on macOS):
{
"mcpServers": {
"cadquery": {
"command": "cadquery-mcp"
}
}
}Note: If using conda/mamba, you may need to specify the full path:
{
"mcpServers": {
"cadquery": {
"command": "/path/to/conda/envs/yourenv/bin/cadquery-mcp"
}
}
}Once configured, you can ask Claude to create 3D models:
"Create a box with a hole through it"
Claude will execute:
import cadquery as cq
result = (
cq.Workplane('XY')
.box(20, 20, 10)
.faces('>Z')
.workplane()
.hole(5)
)The render tool returns a PNG image to the MCP client. Image display and
saving depend on the client. To request an SVG line drawing, set image_format
to svg; SVG shows geometry outlines without part colors.
For example, pass these arguments to the render tool:
{
"code": "import cadquery as cq\nresult = cq.Workplane('XY').box(10, 20, 30)",
"image_format": "png",
"view": "isometric",
"width": 800,
"height": 600
}PNG output is available through render. The export tool writes CAD files
and SVG drawings; it does not support PNG.
For complex models, request multiple views:
"Show me this bracket from multiple angles"
The server will return isometric, front, top, and right views.
CadQuery scripts can define parameters:
height = 10.0 # Height of the box
width = 20.0 # Width of the box
depth = 5.0 # Depth of the box
import cadquery as cq
result = cq.Workplane('XY').box(width, height, depth)Use the get_parameters tool to extract these for modification.
Export to STEP for manufacturing or STL for 3D printing:
"Export this model as a STEP file to ~/models/bracket.step"
Execute CadQuery code and return rendered image(s).
| Parameter | Type | Default | Description |
|---|---|---|---|
| code | string | required | CadQuery Python code to execute |
| image_format | string | "png" | Shaded PNG with colors, or SVG line drawing |
| view | string | "isometric" | Camera angle (isometric, isometric_back, front, back, top, bottom, left, right) |
| multi_view | boolean | false | Return multiple views |
| width | integer | 800 | Image width in pixels |
| height | integer | 600 | Image height in pixels |
| show_hidden | boolean | true | Show hidden lines in SVG; unused for PNG |
Image width and height must be integers from 16 through 4096. PNG rendering uses VTK's offscreen OpenGL backend; a working graphics backend is required. Explicit SVG rendering does not require a display. PNG failures are returned as errors, rather than silently falling back to SVG.
Get geometry information about the resulting shape.
| Parameter | Type | Default | Description |
|---|---|---|---|
| code | string | required | CadQuery Python code to execute |
Extract customizable parameters from a script.
| Parameter | Type | Default | Description |
|---|---|---|---|
| code | string | required | CadQuery Python code to parse |
Export the model to a file. ~ expands to the server user's home directory;
relative paths are interpreted from the server's working directory. Successful
exports report the absolute destination path. Parent directories must exist.
If the destination is a symlink, a successful export replaces the link and leaves
its target unchanged. Supply format when the filename has no extension.
| Parameter | Type | Default | Description |
|---|---|---|---|
| code | string | required | CadQuery Python code to execute |
| filename | string | required | Output filename |
| format | string | auto | Export format (STEP, STL, SVG, DXF, AMF, 3MF, VRML, BREP) |
Scripts should either:
-
Assign the final shape to a variable named
result:result = cq.Workplane('XY').box(1, 2, 3)
-
Use
show_object()to output shapes:box = cq.Workplane('XY').box(1, 2, 3) show_object(box)
show_object(shape, name="mounting_plate") preserves the supplied name in STEP
exports. Unnamed outputs use object_0, object_1, and so on. Duplicate names
receive numeric suffixes such as _2, while preserving other supplied names.
show_object() accepts CQ-editor-style display options. color accepts RGB or
RGBA tuples, color names, and cq.Color objects. The first RGB component sets
the scale: integers use 0–255; floats use 0–1. In byte RGB tuples, an integer
fourth component also uses 0–255 (128 is approximately half opaque); a float
fourth component uses 0–1. In normalized RGB tuples, the fourth component uses
0–1, including integer 0 and 1.
alpha is opacity from 0 (fully transparent) to 1 (fully opaque), matching
current CQ-editor, and overrides opacity embedded in color. The rgba option
accepts (r, g, b, opacity) and overrides both color and alpha. Its RGB values
follow the same scaling rule, but its opacity always uses 0–1. For example:
show_object(result, options={"color": (64, 164, 223), "alpha": 0.75})Assemblies may be assigned to result or passed to show_object(). Multiple
displayed objects are collected into an assembly, including display colors:
import cadquery as cq
result = cq.Assembly(name="example")
result.add(cq.Workplane("XY").box(10, 10, 10), name="red_block",
color=cq.Color("red"))
result.add(cq.Workplane("XY").box(5, 5, 5), name="blue_block",
loc=cq.Location((20, 0, 0)), color=cq.Color("blue"))Apache License 2.0 - see LICENSE for details.
Contributions are welcome! Please see the cadquery-contrib repository for guidelines.