OpenSCAD MCP Server
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| OPENSCAD_PATH | No | Path to OpenSCAD executable | /usr/bin/openscad |
| MCP_SERVER_NAME | No | MCP server name | openscad-mcp |
| OPENSCAD_TIMEOUT | No | Timeout for rendering operations (seconds) | 30 |
| MCP_SERVER_VERSION | No | MCP server version | 1.0.0 |
| MCP_SERVER_TRANSPORT | No | Transport: stdio, sse, or http | stdio |
| MCP_RENDER_DEFAULT_WIDTH | No | Default image width | 800 |
| MCP_RENDER_DEFAULT_HEIGHT | No | Default image height | 600 |
| MCP_RENDER_MAX_CONCURRENT | No | Max concurrent renders | 4 |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tasks | {
"list": {},
"cancel": {},
"requests": {
"tools": {
"call": {}
},
"prompts": {
"get": {}
},
"resources": {
"read": {}
}
}
} |
| tools | {
"listChanged": true
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
| experimental | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| 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 |
| 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 |
| 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. |
| 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 |
| 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 |
| 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. |
| 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). |
| 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. |
| 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. |
| 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. |
| 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. |
| checkA | 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. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
| conventions_resource | Assembly and coordinate conventions the model should follow. |
| cheatsheet_resource | OpenSCAD syntax reminders for things language models get wrong. |
| get_server_info | Get server configuration and capabilities. |
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.