OpenSCAD MCP Server
This MCP server lets AI assistants design, analyze, and validate 3D-printable models in OpenSCAD.
Render OpenSCAD code or files as images with customizable views, camera, size, quality, color scheme, and variables.
Render multiple standard perspectives (front, back, left, right, top, bottom, isometric) in one call, and compare before/after versions.
Check assemblies for interference, clearance, contact, alignment, motion, and run rule-based YAML/JSON check files.
Export models to STL, 3MF, AMF, OFF, DXF, SVG, PDF, or CSG, optionally with multiple parts bundled.
Create, read, update, list, and delete OpenSCAD model files in a workspace.
Measure geometry: bounding box, volume, surface area, section contours, mass, center of mass, inertia, probes, features (holes), printability, orientation, and anchors.
Validate SCAD syntax, geometry, predicates, includes (with BOSL2 lint), and printability rules.
Evaluate arbitrary SCAD expressions in a model's variable scope.
Access engineering reference data: fits, fasteners, inserts, bearings, magnets, joints, purchased parts, design rules, materials, cheatsheet.
Discover installed OpenSCAD libraries and verify OpenSCAD installation/version.
List project files and trace constant dependencies across includes/uses.
Clear the render cache to force fresh renders.
Provides 3D rendering capabilities for OpenSCAD models, including single view rendering with camera control, multiple perspective generation (orthographic and isometric views), and animation support for 360° model visualization.
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., "@OpenSCAD MCP Server render a cube with dimensions 50x50x50 from a 45-degree angle"
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.
OpenSCAD MCP Server
A Model Context Protocol (MCP) server that lets AI assistants design 3D-printable parts and assemblies in OpenSCAD: render with a stated scale, measure exact geometry, check assemblies for interference and clearance, extract holes and features, judge printability, and export. Built with FastMCP for Python; OpenSCAD 2021.01 is the supported floor and dev snapshots are used when present.
Prerequisites
Related MCP server: 3D MCP Server
Installation
The server is published on PyPI as openscad-mcp, so uv
runs it with no clone and no virtualenv: uvx openscad-mcp. uv keeps a cached
copy; uv tool upgrade openscad-mcp (or uvx openscad-mcp@latest) pulls a
new release, and uvx openscad-mcp@0.6.1 pins one.
Claude Code
Add the server with a single command:
claude mcp add openscad --transport stdio -- uvx openscad-mcpOr, if OpenSCAD is not on your PATH:
claude mcp add openscad --transport stdio \
--env OPENSCAD_PATH=/path/to/openscad -- uvx openscad-mcpUse the --scope flag to control where the configuration is saved:
Scope | Flag | Effect |
Local (default) |
| Available only to you in the current project |
Project |
| Shared with the team via |
User |
| Available to you across all projects |
The repository is also a Claude Code plugin (skill plus server):
/plugin marketplace add robertcoop/openscad-mcp then
/plugin install openscad-mcp@openscad-mcp.
Claude Desktop
Add to your configuration file:
macOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"openscad": {
"command": "uvx",
"args": ["openscad-mcp"],
"env": {
"OPENSCAD_PATH": "/usr/bin/openscad"
}
}
}
}Then restart Claude Desktop.
Cursor / Windsurf / VS Code
Add a .mcp.json file to your project root:
{
"mcpServers": {
"openscad": {
"command": "uvx",
"args": ["openscad-mcp"]
}
}
}Manual / Standalone
# From PyPI (no install required)
uvx openscad-mcp
# The development version, straight from GitHub
uvx --from git+https://github.com/robertcoop/openscad-mcp.git openscad-mcp
# Or clone and run locally
git clone https://github.com/robertcoop/openscad-mcp.git
cd openscad-mcp
uv run openscad-mcp
# Run an assembly check file from a shell or a Makefile (exit code 0/1/2)
uvx openscad-mcp check checks.yaml --allow /path/to/projectAvailable Tools
Every tool response carries errors, warnings and hints parsed from
OpenSCAD's output. Check them: OpenSCAD exits 0 on a failed assert() or an
unknown module and draws a blank scene.
Rendering
Tool | Description |
| Images with a text digest before each one (camera, view direction, scale, bbox). |
Assemblies
Tool | Description |
| Relations between named parts, exported separately and never unioned: |
Parts are given inline as parts=[{name, code, place?, frame?, ghost?, mass_g?, motion?}] or in a check file (frames, quality, parts, checks, model). Any number in a rule may be a SCAD expression string (point: "[BOLT_R, 0, BASE_H]") evaluated in the model's scope, so checks follow the parameters rather than a copy of them. openscad-mcp check <file.yaml> runs a check file from the shell with a meaningful exit code, so make check is one call.
Export & Model Management
Tool | Description |
| Export to STL, 3MF, AMF, OFF, NEF3, DXF, SVG, PDF or CSG. With |
| `action=create |
Measurement & Validation
Tool | Description |
| Exact numbers from the geometry: |
|
|
| Evaluate expressions in a model's variable scope and get typed values (number, vector, string, bool, range, undef) |
| Sourced engineering data with confidence labels: fits (also bidirectional: |
| Discover installed OpenSCAD libraries |
| Verify OpenSCAD installation, version and capabilities |
Project Support
Tool | Description |
| List |
| Clear the render cache |
Usage Examples
Once connected, ask your AI assistant:
"Render a cube with rounded edges"
"Show me the front and top of this model with a scale bar"
"What is the volume and are there any cavities?"
"Cut a section through the lid at z = 12 and tell me the wall thickness"
"Colour the body and lid differently and ghost the body"
"What clearance should I use for an M3 screw and a press-fit 608 bearing?"
"Compare the model before and after changing the radius to 15"
"Export my gear model to STL"
The server also publishes MCP resources (openscad://conventions,
openscad://cheatsheet, openscad://reference/{topic}) and server
instructions with the coordinate and assembly conventions it expects. A
Claude Code skill lives in skills/openscad-design/SKILL.md and the repo can
be installed as a Claude Code plugin (.claude-plugin/).
Tool Parameters
API.md documents every tool and every parameter. Four parameters account for most of the questions:
parts— a list of{"name": ..., "code": ..., "place": ...}objects, accepted byrender(mode="parts"),measure(mode="parts"),checkandexport_model.codeis the statement that instantiates the part (lid();) andplaceis an optional OpenSCAD transform wrapped around it (translate([0,0,20])). Each part is exported on its own, so its identity survives; an assembly is never unioned.measure(mode="parts")measures each part in its placed position (the response saysframe: "assembly"), the same grammarcheck,renderandexport_modeluse.quality—draft,normal,high, or an integer$fn. It sets$fn/$fa/$fsfor the run. It is a correctness knob, not only a speed one:checkreports a distance smaller than the tessellation error bound asUNRESOLVEDrather than guessing, and the fix is a higher quality.variables— a dict injected as OpenSCAD variables. In the wrapped modes (section, parts,scad_eval) they are appended to the wrapped module body rather than passed with-D, and they are injected at file scope as well, so a constant derived inside an included file still sees them. This is how you set a$previewguard variable for an export.include_paths— extra directories added toOPENSCADPATH. WhenMCP_ALLOWED_PATHSis set, every entry is validated against it, as is every file OpenSCAD actually reads.
Exactly one of scad_content or scad_file is required by every tool that
takes source. All parameter parsers accept multiple input formats (JSON
strings, lists, dicts, CSV) for AI assistant compatibility.
Each image costs roughly 640 vision tokens at 800x600, and image sizes are
clamped to 1568 px on the long edge, above which vision models downscale
anyway. Ask for the views that answer a question rather than all of them.
Auto-fit renders (grounded=false) have no recoverable absolute scale, which
the digest states.
Configuration
Environment Variables
Variable | Description | Default |
| Path to OpenSCAD executable | Auto-detected |
| Temporary file directory |
|
| Transport type: |
|
| Host for HTTP/SSE transport |
|
| Port for HTTP/SSE transport |
|
| Max parallel renders |
|
| Render timeout in seconds |
|
| Enable render caching |
|
| Max cache size in MB |
|
| Cache TTL in hours |
|
| Logging level |
|
| Max SCAD file size |
|
| Directories scripts may read from ( | unset = no validation |
| Address-space limit per OpenSCAD process (POSIX), |
|
| Render size clamp (aspect preserved) |
|
| Pass |
|
YAML Configuration
Create a config.yaml for advanced configuration:
server:
name: "OpenSCAD MCP Server"
version: "0.1.0"
transport: stdio
rendering:
max_concurrent: 5
timeout_seconds: 300
default_color_scheme: Cornfield
cache:
enabled: true
max_size_mb: 500
ttl_hours: 24
security:
rate_limit: 60
max_file_size_mb: 10
allowed_paths: # null = no path validation at all (a warning is logged)
- /home/me/projects/parts
max_memory_mb: 4096Security
Threat model
The server runs OpenSCAD on source it is handed. OpenSCAD can read any file
the process can read, through include <>, use <>, import() and
surface(), and can return what it read as echo output or as geometry. The
guarantees below hold only when allowed_paths is configured. Out of the
box it is unset, no path validation is performed, and the server logs a
warning at startup saying so.
What is enforced:
Path validation on arguments:
scad_file,include_paths(in every tool) and exportoutput_pathmust lie insideallowed_paths. Containment uses resolved paths, so symlinks and..cannot escape.Path validation on the dependency closure: every file OpenSCAD actually read is recorded with
-dand checked after the run. If any lies outsideallowed_paths, the standard library directories, or the server temp dir, the output (image, mesh, echo text) is withheld and the call fails. This closes theinclude <...>-as-data andsurface(file=...)channels.Memory ceiling: each OpenSCAD process runs under
RLIMIT_AS(max_memory_mb, default 4 GB) on POSIX hosts. OpenSCAD has no ceiling of its own; a smallminkowski()can otherwise consume all host memory.Timeout:
timeout_seconds, default 300 s; partial stderr is kept.Echo channel bounds:
echo_outputis capped (200 lines, 2000 chars per line) and labelled as untrusted content from the rendered file.File size limits, variable name validation (
^\$?[a-zA-Z_][a-zA-Z0-9_]*$) and model name validation (no path traversal) as before.
What is not enforced: no OS-level sandbox (no network isolation, no filesystem namespace). For untrusted input run the server inside a container or under Landlock/bubblewrap with only the project directory mounted.
Why --hardwarnings is off
--hardwarnings stops OpenSCAD at the first warning but still exits 0, so
it produced blank renders and silently truncated echo_output with no
indication. Warnings now reach the assistant through the structured
warnings, errors and hints fields on every tool response instead.
Set MCP_HARD_WARNINGS=true to restore the flag.
Development
# Clone the repo
git clone https://github.com/robertcoop/openscad-mcp.git
cd openscad-mcp
# Install dependencies (the dev extra; there is no dependency-groups table,
# so `uv sync --dev` would remove pytest, ruff, black and mypy)
uv sync --extra dev
# Run the server
uv run openscad-mcp
# Run the assembly checker on a check file
uv run openscad-mcp check examples/checks/turntable.yaml
# Run tests
uv run pytest
# Lint & format. The tree carries pre-existing findings, so expect noise;
# CI gates only on `ruff check --select F,E9,B src/openscad_mcp/`.
uv run ruff check src/ tests/
uv run black --check src/ tests/
# Type check (also not clean today)
uv run mypy src/Project Structure
openscad-mcp/
├── src/openscad_mcp/
│ ├── server.py # FastMCP server, the 12 tools, rendering, cache, CLI
│ ├── assembly.py # Part/Frame/Assembly model and the check-file grammar
│ ├── checks.py # RuleEngine: the rules a check file can ask for
│ ├── geom.py # Mesh kernel: BVH, tri-tri distance, winding number, sweeps
│ ├── csgfeatures.py # CSG-dump parser: holes, bosses, cross-part alignment
│ ├── massprops.py # Mass, centre of mass, inertia by tetrahedra
│ ├── printability.py # Overhangs, wall thickness, islands, orientation candidates
│ ├── analysis.py # Static analysis: BOSL2 $var shadowing lint, constant tracing
│ ├── parts_catalog.py # Purchased-parts catalog loader and self-check
│ ├── parts/*.scad # One generated BOSL2 file per catalogued part
│ ├── threemf.py # Multi-object 3MF writer
│ ├── wrappers.py # Source-level wrappers: include hoisting, variable injection
│ ├── diagnostics.py # stderr -> Diagnostics; -d deps parsing; repair hints
│ ├── camera.py # Orthographic camera model, fit, annotation, spatial digest
│ ├── mesh.py # Stdlib STL/SVG analysis: welding, components, volumes
│ ├── reference.py # Sourced engineering data: fits, fasteners, inserts, DFM
│ ├── types.py # Pydantic models and enums
│ └── utils/config.py # Configuration with env/YAML/dotenv support
├── tests/ # ~1,500 tests; 80% coverage floor
├── evals/ # Deterministic geometry eval harness, 15 tasks
├── examples/checks/ # A worked check file and its model
├── skills/openscad-design/ # Claude Code skill: the design loop
└── .claude-plugin/ # Claude Code plugin manifestTesting
# Run all tests with coverage (about 1,500 tests, roughly a minute)
uv run pytest
# Run specific markers: unit, config, integration, slow, performance, edge, render
uv run pytest -m unit
uv run pytest -m performance
uv run pytest -m "not slow"
# Run a single file, without the coverage gate
uv run pytest tests/test_helpers.py -v --no-covMost tests mock the OpenSCAD subprocess, so no OpenSCAD installation is needed
to run the suite. A mock that stands in for a render has to write both output
files OpenSCAD would have written: the -o target and the -d dependency file
that the cache manifest is built from. Tests that do need the real binary skip
themselves when it is absent.
CI runs the suite on Python 3.10 and 3.12 with OpenSCAD 2021.01 and BOSL2
installed, under xvfb-run because PNG export on 2021.01 needs a display. It
also builds the wheel, installs it in a clean environment, and asserts that a
client sees exactly 12 tools. Coverage floor: 80%.
Troubleshooting
OpenSCAD Not Found
# Check if OpenSCAD is installed
which openscad # Linux/macOS
where openscad.exe # Windows
# Set the path explicitly
export OPENSCAD_PATH=/path/to/openscadServer Not Connecting
# Verify the server starts correctly
uvx openscad-mcp
# In Claude Code, check MCP status
/mcpRender Timeout
Increase the timeout:
export MCP_RENDER_TIMEOUT=600"Path not allowed" / "outside the allowed paths"
MCP_ALLOWED_PATHS is set and the file is not under one of its roots. The
check covers arguments and, separately, every file OpenSCAD actually opened, so
a model that lives inside an allowed root but does include <../shared/lib.scad>
outside it is refused and the output is withheld. Add both roots:
export MCP_ALLOWED_PATHS="$HOME/cad:$HOME/cad-shared"Leaving the variable unset disables path validation entirely, which the server logs a warning about at startup. See Threat model.
An export or a measurement comes back empty
The usual cause is a $preview guard: a file that instantiates its geometry
only inside if ($preview) renders in the GUI and exports nothing, because
$preview is false for a render to a file. Pass the guard variable explicitly:
measure(scad_file="part.scad", variables={"$preview": true})A difference() whose first child is smaller than what follows also yields
nothing. validate(mode="syntax") will not catch either one; the exit code is
0 in both cases.
check rows say UNRESOLVED
The distance in question is smaller than the tessellation error of the mesh, so
the answer would be an artefact of $fn rather than of the design. Re-run with
quality="high" or an explicit integer $fn. Every row reports the quality.fn
it was computed at.
A result looks stale
Renders are cached under ~/.cache/openscad-mcp/, keyed on every render
parameter plus a manifest of every file OpenSCAD read. Editing an included file
normally invalidates the entry, but if a response says cached: true and the
number disagrees with the source, clear it:
clear_cache()Renders fail on a headless machine
OpenSCAD 2021.01 needs a display to export PNG even in headless mode. Run the server under a virtual framebuffer:
xvfb-run -a uv run openscad-mcpExports, measurements and checks produce meshes rather than images and do not need a display.
Contributing
Fork the repository
Create a feature branch (
git checkout -b feature/my-feature)Make your changes with tests
Ensure tests pass (
uv run pytest)Open a Pull Request
Commit style: feat:, fix:, docs:, refactor:, chore:
CONTRIBUTING.md covers the module map, how the tests mock OpenSCAD, the design rules that should not be undone, and how to add a parts-catalog entry or a check rule.
License
MIT — see LICENSE
Acknowledgments
OpenSCAD — Programmable CAD software. Everything here is a wrapper around its CLI.
FastMCP — Python MCP framework
Model Context Protocol — The MCP specification
BOSL2 — Used, not vendored, by the purchased-parts catalog and by the BOSL2 anchor probe. BSD-2-Clause; install it separately.
Dimensional data in
referenceandpartsis cited entry by entry, with a confidence label on every number. See src/openscad_mcp/parts/README.md.
Available Tools
12 toolscheckA
Relations between named parts, exported separately (never unioned), cached, in the assembly frame. parts=[{name, code, place?, frame?, ghost?, mass_g?, motion?}] (code "lid();", place "translate(P)") or check_file= (YAML/JSON: frames, quality, parts, checks, model). mode "interference": clear|contact|interference with penetration depth and witness point (flush contact is contact). "clearance": exact minimum distance, closest points, min_mm. "contact": area, normal, plane; kind=static|sliding. "alignment": coaxial hole stacks across parts, offsets, orphans. "motion": sweep moving= about axis/center over range deg, or along vector over range mm; full turns add a certificate. "rules": every rule in the check file; exit_code 0/1/2. Any number or vector in a rule or motion may be a SCAD expression string ("[BOLT_R, 0, BASE_H]") evaluated in the model's scope. quality: draft|normal|high or $fn, echoed per row; distances inside the tessellation error bound are UNRESOLVED. volume=true cross-checks with OpenSCAD's intersection volume.
Inputs: axis, kind, mode, pairs, +19 more. Returns: object
check_openscadA
Verify OpenSCAD installation and return version info.
Args: include_paths: Include searched paths in response ctx: MCP context for logging
Returns: Dict with OpenSCAD installation information
Inputs: include_paths. Returns: object
clear_cacheA
Delete all cached render files and report freed space.
Removes every cached image and its dependency manifest from the configured cache directory. Does nothing (and still reports success) when the cache is disabled or the directory does not exist.
Args: ctx: MCP context for logging
Returns: Dict with success status, cleared_files count, and freed_bytes
Inputs: no named parameters. Returns: object
export_modelA
Export OpenSCAD code or file to a mesh, 2D, or CSG format. With parts=[{name, code, place?}] every part is exported separately (in its assembly position) and bundled into one 3MF with named objects, or into a directory of STLs when output_format="stl"; a manifest is returned.
Mesh exports (stl, 3mf, amf, off, nef3) also return a "mesh_health" block from OpenSCAD's CGAL statistics: "manifold" is true, false, or null when OpenSCAD did not perform the check. A non-manifold result usually means parts touch along an edge or face; overlap them slightly.
Args: scad_content: OpenSCAD code to export (mutually exclusive with scad_file) scad_file: Path to OpenSCAD file (mutually exclusive with scad_content) output_format: "stl", "3mf", "amf", "off", "nef3" (3D), "dxf", "svg", "pdf" (2D), or "csg" (evaluated CSG tree). Default "stl". output_path: Path to write the exported file. If not specified, a temp directory is used. variables: Variables to pass to OpenSCAD via -D flags include_paths: Additional include paths for OpenSCAD via the OPENSCADPATH environment variable ctx: MCP context for logging
Returns: Dict with success status, output_path, format, file_size_bytes, mesh_health (mesh formats), warnings, errors, and hints
Inputs: parts, quality, scad_file, variables, +4 more. Returns: object
get_librariesA
Discover installed OpenSCAD libraries on the system.
Searches standard OpenSCAD library paths for the current platform, plus the OPENSCADPATH environment variable. For each found library directory, lists subdirectories as libraries and reports file counts, README presence, and main entry files.
This is a read-only operation that does not require OpenSCAD to be installed.
Args: ctx: MCP context for logging
Returns: Dict with success status, library_paths searched, and libraries list with name, path, file_count, has_readme, and main_files for each library
Inputs: no named parameters. Returns: object
get_project_filesA
mode="files": every .scad under project_dir with size/mtime and the include/use/import/surface references of each. mode="trace": the constant dependency graph for symbol= (lexical, file-scope constants only): its definition, what depends on it (direction="downstream") or what it depends on ("upstream"), by depth, and the part files that use them. project_dir must be inside allowed_paths when configured.
Inputs: project_dir (required), mode, symbol, direction. Returns: object
measureA
Exact numbers from a model's geometry (mm). Prefer this over judging a picture. parts=[{name, code, place?, material?, mass_g?}] names assembly parts; coordinates are then in the assembly frame. mode "model": bbox, volume, area, solid/cavity counts, watertight, mesh_health (2D: area/perimeter). "parts": per part plus assembly bbox. "section": cut contours at section_axis=section_offset (mm or an expression). "mass": grams for material/density; with parts= and about_axis=[[point],[dir]] the assembly mass, centre of mass and inertia about the axis (mass_g overrides purchased parts). "probe": points -> solid|air and which part, rays=[[ox,oy,oz,dx,dy,dz]] -> crossings, polyline -> line of sight and blocker. "features": holes from the CSG tree: axis, diameter, depth, undersize at $fn, fit names. "printability": overhang patches with unsupported reach, thickness vs nozzle, islands (layer_height_mm), support estimate; facts only. "orientation": candidate orientations, no winner. "anchors": BOSL2 anchors of part="module();". mesh=existing STL/SVG. quality: draft| normal|high or $fn. response_format: concise|detailed.
Inputs: mesh, mode, part, rays, +17 more. Returns: object
modelA
Manage .scad files in a workspace: action = "create" | "get" | "update" | "list" | "delete". name is the file name (".scad" added); content is the source for create/update. Every response carries an "etag" (content hash) so a later update can be checked against the version last read. template="part:" with action="create" writes a purchased-part module from the parts catalog (see reference(topic="parts")) instead of content. workspace defaults to the server temp models directory; when allowed_paths is configured the workspace must lie inside it.
Inputs: action (required), name, content, template, +1 more. Returns: object
referenceA
Sourced engineering data for 3D-printed parts, each entry with a confidence label (standard / consensus / calibrate). topics: fits (clearances per side and diametral, $slop), fasteners (metric screws, clearance and tap holes), inserts (heat-set), bearings, magnets, joints (dovetail, snap, press, hinge; BOSL2 module names), parts (purchased-part catalog: envelope, mount pattern, shaft, mass, a BOSL2 module with named anchors and a clearance mask; write it with model(action=create, template="part:")), conventions, cheatsheet, dfm (FDM design rules), materials. query filters entries. topic="fits" with diameter_mm=3.3 names what that hole is (top 3 with deltas); with shaft_mm and bore_mm it names the fit class.
Inputs: query, topic, bore_mm, detailed, +2 more. Returns: object
renderB
Images of a model, each preceded by a text digest (view direction, camera, scale, bbox) and followed by metadata with errors/warnings/ hints. Check those: OpenSCAD draws a blank scene and exits 0 on a failed assert or unknown module. mode "views": one image per view (default ["isometric"]; front back left right top bottom isometric dimetric) or a custom camera_position. "section": exact cut at section_axis=section_offset (mm, or an expression in the model's scope). "parts": parts=[{name, code, place?, color?, ghost?, explode?}] in stable colours; isolate=name ghosts the rest. "compare": before/after via variables_after or scad_content_after. grounded=true gives an orthographic view with an exact mm/px scale; annotate=true adds scale bar, axis triad and bbox size; look_at=part | [x,y,z] | {min,max} frames that box; callouts=[{label, at}] label points. Auto-fit views have no absolute scale. quality: draft|normal| high. image_size default 800x600 (~640 tokens per image).
Inputs: mode, parts, views, isolate, +18 more.
scad_evalA
Evaluate OpenSCAD expressions and return typed values (number, vector, string, bool, range, undef). With scad_content/scad_file the expressions run in that model's variable and function scope, so "wall*2 + clearance" or "len(hole_positions)" work; without a model they run standalone. Numbers carry OpenSCAD's 6 significant digits. No geometry is evaluated.
Inputs: expressions (required), scad_file, variables, scad_content, +1 more. Returns: object
validateA
Check a model. "valid" is false whenever an ERROR was reported, whatever OpenSCAD's exit code was. mode: "syntax": parse and evaluate without geometry (fast): errors, warnings, echo_output, hints, unresolved_includes with locations. "geometry": export the mesh and report findings: not watertight, non-manifold, several solids, cavities, empty; with the numbers. "predicates": predicates=["W > 10", ...] evaluated in the model's own scope; each must be true. sweep={variable, values:[..]} re-runs them per value and reports the first failure and the crossing. "includes": every include/use/import/surface reference with its resolved path, plus the BOSL2 lint: a module from a use<>d file placed by attach()/position() is silently put at CENTER; findings carry a fix plan, applied to the file when autofix=true and safe. "printability": rules from reference(topic=dfm) over measure(mode=printability) facts in orientation=; profile= {overhang_deg, nozzle_mm, max_unsupported_reach_mm, min_wall_mm} overrides thresholds. Findings carry magnitude and location.
Inputs: mode, sweep, autofix, profile, +6 more. Returns: object
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 12 tools
Each tool targets a clearly different concern: environment checks, library discovery, expression evaluation, export, rendering, measurement, validation, assembly analysis, and reference data. Some minor overlap exists between measure's watertight/mesh_health output and validate's geometry checks, and between model action=list and get_project_files, but the descriptions make the intended use distinguishable.
The naming convention is mixed: several tools use verb_noun forms like export_model and get_project_files, while render, measure, validate, and check are bare verbs, and model and reference are nouns. The names are still readable and mostly predictable, but there is no single consistent naming convention across the set.
Twelve tools is well within the ideal range for a specialized CAD server, and each tool covers a substantial portion of the OpenSCAD workflow without feeling redundant. The count feels deliberate rather than bloated or sparse.
The tool surface covers the full lifecycle: model file management, project analysis, expression evaluation, rendering, export, measurement, validation, assembly relation checks, reference data lookup, and cache maintenance. No obvious dead ends remain for modeling, analyzing, or verifying designs.
Maintenance
Related MCP Connectors
Parametric 3D CAD for AI agents: build print-ready parts, check them, export STL, 3MF or STEP.
A browser 3D CAD for your AI: it scripts real-size models, uCAD builds them and returns pictures.
Blender and GLB/FBX/USD/STL rendered on cloud GPUs for AI agents: product shots, turntables, MP4
Generate 3D models from images or text with AI, then retexture or convert them to STL, 3MF or OBJ.
Related MCP Servers
- AlicenseAqualityCmaintenanceCreate and edit parametric 3D models with OpenSCAD. Render STL meshes and PNG previews, export SCAD, STL, CSG, and 3MF, and persist model revisions through MCP over stdio or local HTTP. Includes headless Docker support; no GPU or API keys required.8215MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI-driven 3D model generation and manipulation using OpenSCAD through natural language commands. Users can create primitives, apply transformations, perform boolean operations, and export models to various formats like STL and OBJ.6 npmMIT
- AlicenseNot gradedqualityNot gradedmaintenanceEnables AI assistants to render 3D models by providing tools to execute OpenSCAD code and generate single or multi-perspective views. It returns high-quality PNG renderings directly to LLM applications for visual feedback and 3D model visualization.MIT
- AlicenseAqualityDmaintenanceEnables AI assistants to create and manipulate 3D CAD models using OpenSCAD.424 npm1MIT