RobertCoop

OpenSCAD MCP Server

Community RobertCoop
Updated

A Model Context Protocol (MCP) server for OpenSCAD 3D modeling and rendering

OpenSCAD MCP Server

MCPFastMCPTestsCoverageLicense

A Model Context Protocol (MCP) server that gives AI assistants the ability to render, export, and analyze 3D models using OpenSCAD. Built with FastMCP for Python.

Prerequisites

  • OpenSCAD installed on your system
  • uv (recommended) or Python 3.10+

Installation

Claude Code

--refresh-package openscad-mcp makes uv re-resolve the package from GitHubon every start, so a new release is picked up automatically the next time theserver launches. Drop the flag to pin to whatever uv has cached, or add@v0.6.0 after the URL to pin a release.

Add the server with a single command:

claude mcp add openscad --transport stdio -- \
  uv run --refresh-package openscad-mcp --with git+https://github.com/quellant/openscad-mcp.git openscad-mcp

Or, if OpenSCAD is not on your PATH:

claude mcp add openscad --transport stdio \
  --env OPENSCAD_PATH=/path/to/openscad -- \
  uv run --refresh-package openscad-mcp --with git+https://github.com/quellant/openscad-mcp.git openscad-mcp

Use the --scope flag to control where the configuration is saved:

Scope Flag Effect
Local (default) --scope local Available only to you in the current project
Project --scope project Shared with the team via .mcp.json
User --scope user Available to you across all projects

Claude Desktop

Add to your configuration file:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
{
  "mcpServers": {
    "openscad": {
      "command": "uv",
      "args": [
        "run",
        "--refresh-package", "openscad-mcp",
        "--with", "git+https://github.com/quellant/openscad-mcp.git",
        "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": "uv",
      "args": [
        "run",
        "--refresh-package", "openscad-mcp",
        "--with", "git+https://github.com/quellant/openscad-mcp.git",
        "openscad-mcp"
      ]
    }
  }
}

Manual / Standalone

# Run directly from GitHub (no install required)
uv run --refresh-package openscad-mcp --with git+https://github.com/quellant/openscad-mcp.git openscad-mcp

# Or clone and run locally
git clone https://github.com/quellant/openscad-mcp.git
cd openscad-mcp
uv run openscad-mcp

Available Tools

Every tool response carries errors, warnings and hints parsed fromOpenSCAD's output. Check them: OpenSCAD exits 0 on a failed assert() or anunknown module and draws a blank scene.

Rendering

Tool Description
render Images with a text digest before each one (camera, view direction, scale, bbox). mode=views (one image per view, or a custom camera), mode=section (exact cross-section with a scale bar), mode=parts (each part in its own colour, isolate ghosts the rest), mode=compare (before/after). grounded=true gives an orthographic view with a stated mm/px scale; annotate=true adds a scale bar, axis triad and bbox dimensions

Assemblies

Tool Description
check Relations between named parts, exported separately and never unioned: mode=interference (clear / contact / interference with penetration depth and a witness point), clearance (exact minimum distance with closest points), contact (area, normal, plane; `kind=static

Parts are given inline as parts=[{name, code, place?, frame?, ghost?, mass_g?, motion?}] or in a check file (frames, quality, parts, checks, model). 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_model Export to STL, 3MF, AMF, OFF, NEF3, DXF, SVG, PDF or CSG. With parts=[...] every part is exported in its assembly position and bundled into one 3MF with named objects (or a directory of STLs)
model `action=create

Measurement & Validation

Tool Description
measure Exact numbers from the geometry: model (bbox, volume, area, components, watertight, mesh_health), parts, section (contours; the offset may be an expression in the model's scope), mass (grams; with parts= and about_axis= the assembly mass, centre of mass and inertia about an axis, with mass_g overrides for purchased parts), probe (solid/air and which part at points; ray crossings; line of sight along a polyline), features (holes from the CSG tree: axis, diameter, depth, through/blind, undersize at $fn, fit names), printability (overhang patches with unsupported reach, thickness distribution vs nozzle, islands, support estimate; facts only), orientation (candidate orientations, no winner chosen), anchors (BOSL2 anchor frames in the assembly frame). Accepts an existing STL/SVG via mesh
validate mode=syntax, geometry, predicates (with sweep={variable, values} reporting the crossing), includes (references resolved or not, plus the BOSL2 lint: a module from a used file placed by attach() is silently put at CENTER; autofix=true applies the rewrite when it is safe), printability (rules from the design-rule reference over measured facts)
scad_eval Evaluate expressions in a model's variable scope and get typed values (number, vector, string, bool, range, undef)
reference Sourced engineering data with confidence labels: fits (also bidirectional: diameter_mm=3.3 names the hole, shaft_mm+bore_mm names the fit), metric fasteners, heat-set inserts, bearings, magnets, joints, a purchased-parts catalog with BOSL2 modules and clearance masks, FDM design rules, materials, OpenSCAD cheatsheet, conventions
get_libraries Discover installed OpenSCAD libraries
check_openscad Verify OpenSCAD installation, version and capabilities

Project Support

Tool Description
get_project_files List .scad files and their references; mode=trace follows a constant through the project (what depends on it, what it depends on)
clear_cache 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 serverinstructions with the coordinate and assembly conventions it expects. AClaude Code skill lives in skills/openscad-design/SKILL.md and the repo canbe installed as a Claude Code plugin (.claude-plugin/).

Tool Parameters

render
Parameter Type Default Description
scad_content string — OpenSCAD code to render*
scad_file string — Path to .scad file*
mode string views views, section, parts, compare
views list ["isometric"] Any of front, back, left, right, top, bottom, isometric, dimetric
camera_position / camera_target / camera_up list/string — Custom camera (used when views is omitted)
grounded bool false Measure the model, then render orthographically with a stated mm/px scale
annotate bool false Scale bar, axis triad, bbox dimensions (implies grounded)
section_axis / section_offset string / number z / 0 Cut plane for mode=section
parts / isolate list / string — [{"name": "lid", "code": "lid();"}] for mode=parts
variables_after / scad_content_after dict / string — The "after" side for mode=compare
image_size list/string [800,600] Output dimensions, clamped to 1568 px
color_scheme string Cornfield OpenSCAD color scheme
variables dict {} OpenSCAD variables
quality string — draft, normal, or high
include_paths list — Extra include directories (via OPENSCADPATH)

Each image costs roughly 640 vision tokens at 800x600; ask for the views thatanswer a question rather than all of them. Auto-fit renders (grounded=false)have no recoverable absolute scale, which the digest states.

*Exactly one of scad_content or scad_file must be provided.

All parameter parsers accept multiple input formats (JSON strings, lists, dicts, CSV) for AI assistant compatibility.

Configuration

Environment Variables

Variable Description Default
OPENSCAD_PATH Path to OpenSCAD executable Auto-detected
MCP_TEMP_DIR Temporary file directory /tmp/openscad-mcp
MCP_TRANSPORT Transport type: stdio, http, sse stdio
MCP_HOST Host for HTTP/SSE transport localhost
MCP_PORT Port for HTTP/SSE transport 8000
MCP_MAX_CONCURRENT_RENDERS Max parallel renders 5
MCP_RENDER_TIMEOUT Render timeout in seconds 300
MCP_CACHE_ENABLED Enable render caching true
MCP_CACHE_SIZE_MB Max cache size in MB 500
MCP_CACHE_TTL_HOURS Cache TTL in hours 24
MCP_LOG_LEVEL Logging level INFO
MCP_MAX_FILE_SIZE_MB Max SCAD file size 10
MCP_ALLOWED_PATHS Directories scripts may read from (os.pathsep-separated) unset = no validation
MCP_MAX_MEMORY_MB Address-space limit per OpenSCAD process (POSIX), 0 disables 4096
MCP_MAX_IMAGE_WIDTH / MCP_MAX_IMAGE_HEIGHT Render size clamp (aspect preserved) 1568
MCP_HARD_WARNINGS Pass --hardwarnings to OpenSCAD (see Security) false

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: 4096

Security

Threat model

The server runs OpenSCAD on source it is handed. OpenSCAD can read any filethe process can read, through include <>, use <>, import() andsurface(), and can return what it read as echo output or as geometry. Theguarantees below hold only when allowed_paths is configured. Out of thebox it is unset, no path validation is performed, and the server logs awarning at startup saying so.

What is enforced:

  • Path validation on arguments: scad_file, include_paths (in everytool) and export output_path must lie inside allowed_paths. Containmentuses resolved paths, so symlinks and .. cannot escape.
  • Path validation on the dependency closure: every file OpenSCAD actuallyread is recorded with -d and 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. Thiscloses the include <...>-as-data and surface(file=...) channels.
  • Memory ceiling: each OpenSCAD process runs under RLIMIT_AS(max_memory_mb, default 4 GB) on POSIX hosts. OpenSCAD has no ceiling ofits own; a small minkowski() can otherwise consume all host memory.
  • Timeout: timeout_seconds, default 300 s; partial stderr is kept.
  • Echo channel bounds: echo_output is capped (200 lines, 2000 charsper 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 pathtraversal) as before.

What is not enforced: no OS-level sandbox (no network isolation, nofilesystem namespace). For untrusted input run the server inside acontainer or under Landlock/bubblewrap with only the project directorymounted.

Why --hardwarnings is off

--hardwarnings stops OpenSCAD at the first warning but still exits 0, soit produced blank renders and silently truncated echo_output with noindication. Warnings now reach the assistant through the structuredwarnings, 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/quellant/openscad-mcp.git
cd openscad-mcp

# Install dependencies
uv sync --dev

# Run the server
uv run openscad-mcp

# Run tests
uv run pytest

# Lint & format
uv run ruff check src/ tests/
uv run black --check src/ tests/

# Type check
uv run mypy src/

Project Structure

openscad-mcp/
├── src/openscad_mcp/
│   ├── __init__.py          # Package exports
│   ├── server.py            # FastMCP server, all MCP tools and helpers
│   ├── types.py             # Pydantic models and enums
│   └── utils/
│       └── config.py        # Configuration with env/YAML/dotenv support
├── tests/                   # 300 tests, 80%+ coverage
├── pyproject.toml
└── README.md

Testing

# Run all tests with coverage
uv run pytest

# Run specific markers
uv run pytest -m unit
uv run pytest -m performance

# Run a single file
uv run pytest tests/test_helpers.py -v

Tests mock the OpenSCAD subprocess — no OpenSCAD installation required to run them. Coverage target: 80% minimum.

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/openscad

Server Not Connecting

# Verify the server starts correctly
uv run --refresh-package openscad-mcp --with git+https://github.com/quellant/openscad-mcp.git openscad-mcp

# In Claude Code, check MCP status
/mcp

Render Timeout

Increase the timeout:

export MCP_RENDER_TIMEOUT=600

Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/my-feature)
  3. Make your changes with tests
  4. Ensure tests pass (uv run pytest)
  5. Open a Pull Request

Commit style: feat:, fix:, docs:, refactor:, chore:

License

MIT — see LICENSE

Acknowledgments

MCP Server · Populars

MCP Server · New

    gobuildwp

    GoBuildWP: WordPress MCP server and AI website builder for Claude, ChatGPT, Cursor and Codex

    GoBuildWP (formerly WPPilot): WordPress MCP server & AI agent for ChatGPT, Claude, Cursor, Codex. Build and edit full websites in Elementor and Gutenberg, run SEO, PageSpeed checks, safe updates, backups and security, many sites via GoBuildWP Cloud. Safety profiles, human approval, undo. Free core; Pro adds WooCommerce and more builders.

    Community gobuildwp
    AIAnytime

    Awesome MCP Servers

    A curated directory of Model Context Protocol (MCP) servers, plus runnable reference implementations in Python.

    Community AIAnytime
    wiresage

    MikroTik MCP

    MCP server for Mikrotik

    Community wiresage
    n24q02m

    email

    IMAP/SMTP email for AI agents -- read, send, organize folders, and manage attachments across multiple accounts, with auto-discovery.

    Community n24q02m
    reticlehq

    reticle

    AI agents can generate code, but still struggle to understand what they build. Reticle brings Jev-style machine-native runtime perception to web & desktop applications.

    Community reticlehq