cad-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@cad-mcpmake a 19-tooth helical gear with a 12mm bore, verify it's watertight, export STL"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
cad-mcp
An MCP server that lets an LLM design parametric 3D parts — and actually verify they are printable.
Most "AI + CAD" demos stop at generating geometry. That is the easy half. The hard half is that a mesh can look correct in a screenshot and still be a broken solid — and the model has no way to notice.
cad-mcp closes that loop. Every part the model builds is checked for topology before it can be exported, and the verdict comes back as structured numbers (watertight? genus? volume? wall thickness?) instead of a picture the model has to squint at.
you: make me a 19-tooth helical gear with a 12 mm bore
model: make_part("involute_helical_gear", {"teeth": 19, "bore_dia": 12})
→ watertight=True genus=1 volume=31140.45 mm³ 19,912 triangles
└ genus=1 is the check that matters: exactly one through-hole, i.e. the bore.
genus=0 would mean the bore is missing; genus=2 would mean the blank is split.
model: look_at_mesh("gear", views="four") → the image below comes back into the context
export_mesh("gear", ["stl", "obj"]) → out/gear.stl
Rendered by the server itself, in pure NumPy — no OpenGL, no CAD kernel. 19 teeth, module 2.5, 22° helix, 16 mm face width, DIN 6885 keyway. Watertight, genus 1, 31,140.45 mm³.

What a refusal looks like
The interesting case is not a part that builds. It is a part that builds, looks fine, and is not printable. Ask for a lattice with walls thinner than a voxel and this comes back:
{
"ok": false, "watertight": true,
"genus": -928.0, "shells": 737,
"fragmented": true, "volume_mm3": 11.7538,
"warning": "The mesh shattered: 737 disconnected shells, overall genus -928 (negative). This is not a part, it is a pile of flakes; exporting will be refused. Raise the wall thickness or lower res."
}Every signal a human would check says fine: watertight, zero non-manifold edges, positive
volume, and a screenshot that looks like a dense lattice. The mesh is 737 disconnected shards,
each one a perfectly closed surface — which is why only the shell count and the sign of the
whole-mesh genus reveal it. export_mesh then refuses before touching the disk; force=True
overrides, and says so in its return value.
A full session — build, verify, look, change the bore, export, get refused — is recorded in
docs/demo-session.md, generated by scripts/make_session_demo.py
against the real server. Every JSON block in it is an actual tool return value, including an
independent check that predicts a volume the server later reports to 0.01%.
Related MCP server: fcgen-mcp
Install
python -m venv .venv
.venv/bin/pip install -e ".[render]" # Windows: .venv\Scripts\pipcad-mcp needs Python 3.10+ and NumPy. The render extra adds Pillow, which is only required
for the visual half (look_at_mesh). Without it, the modelling and verification tools still work.
There is no CAD kernel, no OpenCASCADE, no trimesh, no compiled extension.
Modelling every built-in part — including the vase, whose radius profile is a smooth spline —
works on that install alone. The spline has two implementations: scipy.interpolate.CubicSpline
when scipy is present, and a built-in NumPy one otherwise. They agree to 4.4e-16, and
tests/test_kernel.py asserts that, because "scipy is optional" is only true if the parts
actually build without it. Verified by installing NumPy alone into a fresh venv: all four parts
build, and the vase comes out with bit-identical vertices (12432×3, max|Δ| = 0.0) and the same
62,960.4021 mm³ as the scipy environment.
Check the install before wiring it into a client:
.venv/bin/python -m cadmcp.server --check # versions, renderer, font, output dirTroubleshooting
Almost always a non-ASCII path on Windows. An editable install works by dropping a .pth
file into site-packages; pip writes it as UTF-8, but site.py decodes it with the locale
encoding (cp936 on a Chinese Windows). The path decodes to mojibake, the directory does not
exist, and Python silently skips it — pip list still shows cad-mcp 0.1.0, so the install
looks fine while the import keeps failing.
Three ways out, best first:
Give the server the source tree directly — no
.pthinvolved. AddPYTHONPATHto the client'senv(see the last config block below).Or do a regular install instead of an editable one:
pip install ".[render]".Or move the checkout somewhere ASCII-only, e.g.
C:\dev\cad-mcp.
Pillow is missing. pip install "cad-mcp[render]". Modelling and verification work without it.
The bundled fallback font has no CJK glyphs. --check prints which font was picked. Point
CADMCP_FONT at any font file that has the glyphs, e.g. C:\Windows\Fonts\msyh.ttc, and pass it
in the client's env.
Configure your client
{
"mcpServers": {
"cad": {
"command": "/absolute/path/to/cad-mcp/.venv/bin/python",
"args": ["-m", "cadmcp.server"],
"env": { "CAD_MCP_OUT": "/absolute/path/to/output/dir" }
}
}
}On Windows the interpreter lives at .venv\Scripts\python.exe, and backslashes in JSON have to
be doubled:
{
"mcpServers": {
"cad": {
"command": "C:\\dev\\cad-mcp\\.venv\\Scripts\\python.exe",
"args": ["-m", "cadmcp.server"],
"env": { "CAD_MCP_OUT": "C:\\dev\\cad-mcp\\out" }
}
}
}claude mcp add cad -- /absolute/path/to/cad-mcp/.venv/bin/python -m cadmcp.serverRun the server as a subprocess and speak MCP over stdin/stdout:
command: /absolute/path/to/cad-mcp/.venv/bin/python
args: ["-m", "cadmcp.server"]
env: CAD_MCP_OUT=/absolute/path/to/output/dir # optional, defaults to ./outCAD_MCP_OUT is the only knob. Everything the server writes — STL, OBJ, PNG, GIF — lands there.
That is the whole setup. If you would rather run the server straight out of a checkout without
pip install -e ".[render]", point Python at the source tree instead:
{
"mcpServers": {
"cad": {
"command": "/absolute/path/to/cad-mcp/.venv/bin/python",
"args": ["-m", "cadmcp.server"],
"env": {
"PYTHONPATH": "/absolute/path/to/cad-mcp/src",
"CAD_MCP_OUT": "/absolute/path/to/output/dir"
}
}
}
}The seven tools
Tool | What it does |
| Lists the built-in parametric parts and their parameters, with defaults and ranges read from the implementation, so the model never has to guess an argument name |
| Instantiates a parametric part ( |
| Builds free-form geometry from signed distance fields: spheres, boxes, gyroid / Schwarz-P TPMS lattices, shells, with optional corner notches to expose the interior. Reports |
| Re-runs the topology report, cuts cross-sections, estimates minimum wall thickness — pass/fail gates for printability. Reports |
| Renders one or more viewpoints (or a turntable GIF) and returns the images as MCP image content, so the model sees its own work |
| Writes binary/ASCII STL or OBJ+MTL. Refuses at the gate: non-manifold edges, non-positive volume, NaN vertices, or a fragmented shell are blocked before anything touches the disk. Non-watertight only warns. Override with |
| Replays a session model: the exact parameters it was built from, its topology, and every artifact on disk. This is what makes "now make the bore 14 mm" work without the model having to remember its own earlier tool call |
Arguments like involute_helical_gear(teeth=19, module=2.5, helix_deg=22) are validated against
the real signature — call it with teath=19 and you get
involute_helical_gear 不认识这些参数: ['teath'] instead of a silently wrong gear.
One thing worth knowing when writing a client: a wrong type is caught earlier, by the SDK's
own argument validation, and comes back as isError=true with a plain-text message — there is no
JSON body for that case. Only the field name reaches the server log. So parse the JSON payload of
a tool result, but check isError first.
Why the verification numbers are trustworthy
cad-mcp does not grade its own homework. The checks below compare the tessellated mesh against
closed-form results computed independently of the mesher, so a bug in the mesher cannot
cancel itself out. All values are reproducible with python scripts/make_verification.py
and stored in docs/verification.json.
Check | Measured | Independent value | Error |
Gear circular tooth thickness at the pitch circle | 3.92488 mm | πm/2 − backlash/2 = 3.90699 mm | +0.458 % |
SDF sphere volume, r = 10 mm, 96³ grid | 4184.7218 mm³ | 4/3·πr³ = 4188.7902 mm³ | 0.097 % |
Binary STL round-trip (gear, 19,912 tris) | 995,684 bytes, volume Δ 0.0 mm³ | 84 + 50n = 995,684 bytes | exact |
Gear minimum wall thickness (240 samples) | 2.1124 mm (p05 = 2.4258, median = 7.5016) | — | — |
The residual 0.458 % on tooth thickness is not a bug: it is the polygon approximation of the
involute flank at the pitch circle (12 flank samples per tooth). Tightening flank_samples
converges it toward πm/2, which is exactly the behaviour you want a validator to show.
Every part below is watertight with zero non-manifold edges:
Part | Triangles | Genus | Volume | Notes |
| 19,912 | 1 | 31,140.45 mm³ | genus 1 = the bore, nothing else |
| 24,860 | 0 | 62,960.36 mm³ | hollow, superellipse cross-section |
| 18,480 | 1 | 125,254.19 mm³ | swept tube, self-intersection free |
| 128,284 | 87 | — | 33.3 % solid fraction |
SDF gyroid, 64³ grid | 33,900 | 197 | 2,682.08 mm³ | 20 mm cube, 0.625 mm voxels |
Speed
Single-threaded, pure NumPy, on an ordinary desktop CPU (scripts/make_verification.py):
Operation | Time |
| 0.54 s |
| 0.09 s |
| 0.07 s |
| 0.003 s |
| 0.009 s |
| 3.5 s |
| 2.3 s |
| 4.5 s |
Modelling is cheap; rendering is the slow part, which is why look_at_mesh takes a views
count and a size — ask for one 640×480 view while iterating, four larger ones when you are done.
What is inside
src/cadmcp/
├── geom.py 34 KB Mesh, welding, topology report (Euler characteristic, genus,
│ manifold audit), slicing, min wall thickness, ear-clipping,
│ solid/tube sweeps
├── models.py 16 KB the four parametric parts, involute flanks + root fillets
├── implicit.py 36 KB SDF primitives, booleans, smooth min/max, twists, gyroid /
│ Schwarz-P, surface-nets mesher
├── render.py 52 KB software rasteriser: supersampled triangle fill, Phong shading,
│ contact shadows, ground pool, perspective/ortho cameras,
│ turntables, multi-view grids
├── meshio.py 5 KB binary/ASCII STL, OBJ+MTL round-trip
└── server.py the MCP layerThe kernel is deliberately analytic where it can be, numeric where it must be: parametric parts are exact sweeps of closed profiles, while lattices come out of an implicit field.
Four implementation notes that cost real debugging time, in case you fork this:
sdf_to_mesh(f, lo, hi, res)takes a resolution count per axis, not a voxel size. Passing a voxel size (~0.3) makesmin(nx,ny,nz) < 2and the mesher refuses. The compute domain is also padded 12 % so the iso-surface never touches the boundary.Pillow's built-in font has no CJK glyphs. Every Chinese label in a
render_gridcame out as□□□— in the exact images meant for this README. The renderer now resolves a system CJK font (Microsoft YaHei / SimHei / PingFang / Noto CJK), centres the label on its real glyph bbox, and exposesfont_supports_cjk()so callers can fall back to English. Override withCADMCP_FONT.A watertight mesh can still be garbage. Set a lattice wall thinner than one voxel and the surface-nets mesher happily returns 737 disconnected shards — every one of them a perfectly closed surface,
watertight=True,non_manifold_edges=0, positive volume. Every "does it look broken?" signal says no. What catches it is the shell count, plus the fact that genus, being a whole-mesh formula (g = (2 − χ)/2), turns negative when the mesh is really a pile of fragments. That is whyexport_meshrefuses onfragmentedand whycheck_meshreportsshells— the shard detection is the check that a picture could never have made.Vertex normals belong to a smoothing sector, not to a vertex. The gear rendered with a fine vertical stipple across its hub and tooth tips while flat panels and every other part came out clean. Three hypotheses died on data first: six
specular/shininesscombinations, eight tessellation settings, and crease angles from 5° to 90° all produced the identical stipple — the last one because a fixed count of 92 edges sit at exactly 180°, independent of sampling. The cause was real: normals were one area-weighted average over every incident face, and the hub cylinder's vertices sit directly against a coplanar annular face, which dragged the average toward +Z. Measured on the tip cylinder, normals deviated from radial by a median of 26.4° and up to 81.2°. They are now accumulated per smoothing sector — connected components along non-hard edges, the equivalent of a smoothing group. Smooth surfaces collapse back to one sector, so the fix is provably inert where it should be, andtests/test_kernel.pyasserts both directions: the torus knot matches the naive average to 1e-6°, the gear does not.
Development
python tests/test_e2e_stdio.py # 62 checks, drives a real server subprocess over stdio
python tests/test_kernel.py # geometry kernel unit tests
python scripts/preflight.py # 54 checks that every claim in THIS README still holds
python scripts/make_demo.py # regenerate docs/gallery.png + docs/gear-turntable.gif
python scripts/make_verification.py # regenerate docs/verification.json
python scripts/make_session_demo.py # regenerate docs/demo-session.mdscripts/preflight.py exists because a README is the part of a project that rots silently. Code
gets refactored, an argument is renamed, a verification number is recomputed — and no unit test
notices, because unit tests test code. So every factual claim in this file is an assertion: it
checks that each referenced file exists, that the numbers printed in the verification table match
docs/verification.json character for character, that CI really runs both test scripts on all
three platforms, and that the four built-in parts still build with the genus this README claims.
The end-to-end test is not a mock: it spawns python -m cadmcp.server, speaks the real MCP
protocol over stdio, calls every tool, and asserts that look_at_mesh returns an image
content block before the text summary — that ordering is what makes the model look at the
picture instead of skipping it.
Both test scripts reconfigure their output to UTF-8 on startup. A Chinese Windows console
defaults to cp936, where a single mm³ in an assertion message raises UnicodeEncodeError —
turning a clean pass/fail report into a stack trace. CI hides this behind
PYTHONIOENCODING: utf-8; running the tests locally does not, so they fix it themselves.
Limitations
Three parts families, not a general CAD kernel. No fillets/chamfers on arbitrary edges, no B-rep booleans, no constraints or assemblies.
Models live in server memory for the session. Restart the server and they are gone — export what you want to keep.
look_at_meshneeds Pillow; the modelling and verification tools do not.STL/OBJ only. No STEP, so nothing here round-trips back into a parametric CAD system.
SDF meshing is grid-bound: sharp features below one voxel are lost, and
resis a memory knob as much as a quality knob (capped at 200 M voxels).
License
MIT — see LICENSE.
Available Tools
7 toolscheck_meshA
Geometrically inspect a model you already built; returns numeric evidence you can use to decide whether it came out right.
Includes watertightness, orientation consistency, Euler characteristic, genus, volume, surface area and bounding box. genus tells you whether the hole count is right (a part with one through-hole has genus=1, a solid has genus=0, a lattice coupon is high). It is a topological invariant, which makes it far more reliable than "looks about right". slices: z heights in mm to also measure cross-section areas; wall_samples>0 samples the minimum wall thickness.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| slices | No | ||
| wall_samples | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. 'Inspect' strongly implies a read-only, non-mutating operation and the output list is transparent, but it never explicitly confirms safety, and it omits any cost or performance warning for the potentially expensive wall_samples sampling mode.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose and output list are front-loaded in the first two sentences, and the optional-parameter behavior is grouped at the end. The genus paragraph is useful but slightly verbose, with a mild sales pitch ('far more reliable than "looks about right"') that is not strictly necessary.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema or annotation coverage, so the description must convey return content, and it does so by enumerating every metric returned plus the semantics of genus. It is nearly complete for this inspection tool; only the 'name' parameter and any cost caveats remain unaddressed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must compensate, and it does for two of three parameters: slices is explained as 'z heights in mm to also measure cross-section areas' and wall_samples as sampling minimum wall thickness when >0. The required 'name' parameter is left undefined, though its meaning is self-evident from context.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence names a specific verb and resource ('Geometrically inspect a model you already built') and enumerates the concrete outputs (watertightness, genus, volume, etc.), so an agent knows exactly what comes back. It does not explicitly contrast itself with the similar-sounding siblings look_at_mesh or describe_model, leaving that differentiation to inference.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a clear context of use: 'returns numeric evidence you can use to decide whether it came out right,' and notes the optional slices/wall_samples modes for deeper checks. It does not state when NOT to use it or name an alternative sibling, so the routing guidance is incomplete.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
describe_modelB
Full information about a model you built: parameters, topology, bounding box, files.
Use it mid-session to recall which parameters this model was actually built from.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It usefully discloses the kinds of information returned, but does not state that the operation is read-only, whether it has side effects, what happens if the model does not exist, or any permission requirements.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two short sentences with no wasted text, and it front-loads the returned information before the usage note. It could be slightly more structured, but it is efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description must explain return values, and it does list major categories. It remains incomplete for the single required parameter and for error or not-found behavior, leaving some gaps for an agent invoking the tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is one required parameter, 'name', with 0% schema description coverage. The description implies the name identifies 'a model you built', but does not explain the expected format, uniqueness, or source of the name, so it fails to compensate for the missing parameter documentation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific retrieval action and enumerates what information is returned: parameters, topology, bounding box, and files. It is clearly a metadata lookup for a built model, though it does not explicitly name how it differs from siblings like list_parts or check_mesh.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a concrete usage occasion: mid-session, to recall the parameters a model was built from. However, it does not name alternatives or describe when not to use this tool, leaving routing guidance implicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
export_meshA
Export the model as files for downstream tools: STL (printing / slicing), OBJ+MTL (DCC).
Defaults to both STL and OBJ. There is a hard gate before anything is written: structural damage -- non-manifold edges, non-positive volume, NaN vertices, a fragmented shell -- is refused, because such a mesh punches holes in a slicer or errors out. Watertightness only warns (some shapes are meant to be open). Pass force=True to override.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| force | No | ||
| formats | No | ||
| stl_binary | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses a hard pre-write gate (non-manifold edges, non-positive volume, NaN vertices, fragmented shell are refused), distinguishes that watertightness only warns, and documents the force override. It stops short of stating where files are written, whether existing files are overwritten, or what is returned.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core action and format list, then the gate behavior. Every sentence carries information, though the gate explanation is dense and could be trimmed slightly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 4-parameter mutation tool with no output schema and no annotations, the description covers validation/override behavior well but omits the required `name` parameter's meaning, the stl_binary toggle, and any return/output location, leaving gaps an agent must guess at.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It documents formats and force (including the gate override), but leaves the required `name` parameter and `stl_binary` (binary vs ASCII STL) entirely unexplained, so it only partially closes the coverage gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (export) and resource (the model) and names the concrete output formats (STL for printing/slicing, OBJ+MTL for DCC), which is exactly the kind of differentiation needed against siblings like check_mesh and look_at_mesh. An agent can tell what this produces without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explains the selection context (downstream tools), the default of both formats, and the force=True override for the validation gate. It does not explicitly route to siblings such as check_mesh as a pre-flight step, but the when-to-use and override conditions are clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_partsA
List the built-in parametric parts and their tunable parameters (with defaults and types).
Call this before modelling to get the exact parameter names -- guessing one raises unknown_parameter.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the load and does disclose a real failure mode (guessing a parameter raises unknown_parameter) and the shape of the return (parameter names with defaults and types). It is implicitly a safe read, though it never says so outright.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, zero waste, with the primary action first and the workflow hint second. Nothing padded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter discovery tool with no output schema, the description covers what it returns and why to call it before modelling. An agent has everything needed to invoke it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4. The description adds that the listed entries expose tunable parameters with defaults and types, which is useful context about what the caller gets back.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (List) and resource (built-in parametric parts) plus scope (tunable parameters with defaults and types). It is clearly a discovery tool, distinct from the make_part/make_lattice siblings that create geometry.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use guidance: 'Call this before modelling to get the exact parameter names.' It even states the consequence of skipping it (unknown_parameter). No explicit when-not or named alternative, but the context is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
look_at_meshB
Render the model and return the image directly to you -- this is the core of self-verification.
The render comes back as image content, so you can actually see what you built and decide what to change.
views: 'four' (a 2x2 montage; start here) / 'single' (one viewpoint) / 'grid' (six). turntable_frames>0 also writes a turntable GIF for the human, and returns its path. Returns [image, ...] followed by a JSON summary -- the image always comes first.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| size | No | ||
| views | No | four | |
| azimuth | No | ||
| shading | No | phong | |
| elevation | No | ||
| wireframe | No | ||
| turntable_frames | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden and does well: it discloses that the render returns image content, that the image always precedes the JSON summary, and that turntable_frames>0 writes a GIF file for the human and returns its path. It does not cover error behavior or mesh-missing cases, but the key side effect and return ordering are explicit.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core render-and-return purpose is front-loaded with bold emphasis, and the remaining guidance is compact. The structure is easy to scan, though slightly informal.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a render tool with no output schema and no annotations, the description adequately explains the return format and two parameters. However, six of eight parameters have no semantics anywhere, and there is no mention of prerequisites or failure modes, so it is only minimally sufficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% across 8 parameters, so the description must compensate. It only explains views ('four'/'single'/'grid') and turntable_frames behavior; name, size, azimuth, shading, elevation, and wireframe remain entirely undocumented, leaving most parameters opaque.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (render) and resource (model), and frames the purpose as self-verification. It does not explicitly differentiate from sibling check_mesh or describe_model, but the action is unambiguous without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description recommends 'views: four' as the starting point, implying primary usage. However, it gives no explicit when-not condition or comparison to siblings like check_mesh, leaving the agent to infer when rendering is preferable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
make_latticeA
Model free-form geometry with signed distance fields: lattices, porous structures, implicit surfaces.
primitive: sphere / box / rounded_box / gyroid / schwarz_p. size_mm: the part's bounding box in mm. A single number means a cube with that edge length, [x, y, z] an arbitrary box; omit it to use cell_mm as a cube. res: samples per axis -- a precision knob, not a dimension. Start at 64; 128 is fine but 8x slower. The resulting voxel edge (size/res) is reported back. wall_mm: wall thickness for shells and lattices; period_mm: lattice period (defaults to cell_mm). lattice: shell (hollow it out) / gyroid_grading (fill the interior with lattice). subtract: corner_notch / corner_notch2 (cut a corner away to expose the interior).
| Name | Required | Description | Default |
|---|---|---|---|
| res | No | ||
| name | No | ||
| cell_mm | No | ||
| lattice | No | ||
| size_mm | No | ||
| wall_mm | No | ||
| subtract | No | ||
| period_mm | No | ||
| primitive | No | gyroid |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does disclose useful behavior: res is called out as a precision knob with an 8x-slower cost at 128, and the resulting voxel edge is reported back. However, it says nothing about persistence (whether a part is saved under name), permissions, or what a failure looks like, leaving meaningful gaps for an operation that creates geometry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in one sentence, then parameters are documented as tight labeled lines with no filler. Every line adds a fact an agent needs (defaults, units, speed tradeoff) rather than restating the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 9-parameter, zero-annotation, no-output-schema tool, the description covers parameters well but leaves the agent unsure what the call produces (a stored part? geometry?) and what 'name' does. It is adequate but not fully self-sufficient for a tool this complex.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0% and parameter titles are bare, so the description is the sole source of meaning, and it delivers: primitive enumerations, the number-vs-[x,y,z] polymorphism of size_mm, the size/res voxel relationship, and the period_mm-defaults-to-cell_mm coupling. Only 'name' goes unexplained, which is a minor omission against otherwise excellent compensation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening line states a specific verb+resource: 'Model free-form geometry with signed distance fields: lattices, porous structures, implicit surfaces.' An agent can tell this is the geometry-generation tool, distinct from sibling utilities like check_mesh or describe_model. It does not explicitly contrast with make_part, which is the most likely point of confusion, so it falls short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives operational guidance ('Start at 64', 'omit it to use cell_mm as a cube') but never says when to choose this tool over make_part or when a lattice vs. shell is appropriate. Usage is implied through parameter notes rather than stated selection criteria.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
make_partB
Build a part from the built-in parametric library (gear / vase / torus knot / lattice coupon).
Returns a topology verdict. See list_parts for valid part values; an unknown key in params
is reported explicitly rather than silently ignored. The model is stored in the session and
referenced by name from the other tools.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | ||
| part | Yes | ||
| params | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does disclose some behavior: it returns a topology verdict, unknown `params` keys are reported explicitly rather than silently ignored, and the result is session-stored. It omits anything about failure modes, auth, or whether the build consumes resources, so it is only partially transparent for a mutation-style tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with the core action followed by return value and session semantics. No filler, though the parenthetical example list is slightly dense.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema and no annotations, so the description must do more work. It covers the return type at a high level (topology verdict) and the session model, but leaves `params` structure and error behavior unspecified for a 3-parameter build tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must compensate. It does add meaning for each of the three params — `part` values come from list_parts, `name` is the session handle used by other tools, and `params` rejects unknown keys — but it never describes the shape or expected keys of `params`, leaving the main data-carrying parameter under-specified.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Build a part from the built-in parametric library') and enumerates concrete examples (gear / vase / torus knot / lattice coupon). It does not explicitly differentiate itself from the sibling make_lattice, which is the closest overlap, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Routes the agent to list_parts for valid `part` values and notes the model can be referenced by other tools, which implies downstream usage. However there is no explicit when-to-use vs make_lattice, and no statement of prerequisites or when-not to call it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
7 tool updates
v0.1.0- First observed
check_mesh - First observed
describe_model - First observed
export_mesh - First observed
list_parts - First observed
look_at_mesh - First observed
make_lattice - First observed
make_part
TDQS
Scored across 7 tools
The three build/inspect verbs are well-separated: make_part (library parts) vs make_lattice (free-form SDF) vs list_parts (discovery). check_mesh, look_at_mesh, and describe_model overlap somewhat (all report topology/bbox), but their descriptions clearly split numeric evidence, visual rendering, and parameter recall.
Nearly all names follow a verb_object snake_case pattern (list_parts, make_part, check_mesh, export_mesh, describe_model). The sole deviation is look_at_mesh, which inserts a preposition but remains easily readable.
Seven tools is well-scoped for a model-build-inspect-export workflow; each tool covers a distinct stage and none feels redundant or padded.
Covers discovery, two build paths, numeric and visual verification, export, and parameter recall. Minor gaps: no delete_model, no list_models to enumerate session models, and no pure edit/parameter-update tool, though rebuilding via make_part/make_lattice can work around these.
Maintenance
Related MCP Connectors
- OwlCADOAuthcom.owlcad
Parametric 3D CAD for AI agents: build print-ready parts, check them, export STL, 3MF or STEP.
Design 3D-printable parts by chatting: create, edit, render and publish parametric forges.
Agent-first CAD: editable .kcad.ts source, deterministic review, OpenCASCADE kernel.
Real 3D-print slicing, quoting, DFM, orientation & material/settings advisors. Free personal tier.
Related MCP Servers
- FlicenseNot gradedqualityFmaintenanceEnables conversational 3D modeling by providing CAD-Query functionality to validate parametric 3D models against criteria and export to STL/STEP formats for 3D printing and CAD applications.20-
- AlicenseNot gradedqualityDmaintenanceEnables LLMs to safely generate parametric CAD parts (STEP/STL) using verified templates and FreeCAD, with validation and assembly support.MIT
- AlicenseAqualityCmaintenanceEnables to create, iterate, and export 3D models through natural language conversations with an LLM by bundling OpenSCAD via WebAssembly for zero-setup 3D modeling.1029 npm3GPL 2.0
- AlicenseNot gradedqualityCmaintenanceExposes OpenSCAD CLI as MCP tools for validating, rendering, and exporting parametric 3D models. Enables LLM clients to interactively create and manipulate OpenSCAD designs.4MIT