Project deep-dive

OpenSCAD MCP Server

Talk to Claude. · Print in 3D.

A lightweight MCP server written in Rust that bridges Claude and OpenSCAD — describe a part in plain language, get back rendered previews and print-ready STL files. Runs entirely on your machine, no auth required.

Overview

OpenSCAD MCP Server came out of two things colliding: a 3D printer sitting on my desk and a growing habit of designing everything through conversation with Claude. The gap between "describe a part" and "have a file ready to print" was a few too many manual steps.

The server speaks the Model Context Protocol over stdio — Claude Desktop treats it as a native tool. Ask for a parametric bracket, a cable clip, or a custom enclosure; the server writes the OpenSCAD source, renders a PNG preview directly back into the chat, and exports an STL when you're ready to print.

Everything stays local. No API keys, no cloud rendering, no accounts. The server is a single statically-linked binary — build it once with cargo build --release and drop it in your Claude Desktop config.

A personal project built for scratching the maker + AI tooling itch.

3 MCP Tools
~10MB Memory at rest
0 External dependencies
Printed door knob cover on an actual door knob Multi-angle render grid of the door knob cover Claude iterating on the design in chat
From conversation to printed part (click to expand)
Printed door knob cover Multi-angle render grid Claude iterating on the design

How it works

Three steps from idea to printable file — all inside the Claude chat window.

1
Describe what you want Tell Claude what to model in plain English — dimensions, shape, functional requirements. No OpenSCAD knowledge needed on your end.
2
Claude writes and renders Claude calls write_scad to generate the parametric source file, then render_preview to produce a PNG — which appears inline in the chat. Iterate with natural language: "make the walls 2mm thicker", "add a mounting slot on the back".
3
Export and print When the preview looks right, ask Claude to export. export_stl invokes the OpenSCAD CLI to produce a print-ready STL in ~/.openscad-mcp/ — open it in your slicer and go.

Exposed MCP tools

write_scad

Writes OpenSCAD source to ~/.openscad-mcp/<filename>.scad. Takes a filename and OpenSCAD code string. All file operations are owned by the manager — no path traversal possible.

render_preview

Invokes the OpenSCAD CLI to render the SCAD file to a PNG preview. Returns the image path so Claude can display it inline. Async — doesn't block while OpenSCAD renders.

export_stl

Exports the SCAD source to an STL file ready for slicing. Takes both a source filename and an output name so you can version exports without overwriting the working file.

Architecture

Small surface area by design — two source files, one working directory, one transport.

%%{init: {'theme': 'base', 'themeVariables': {'fontSize': '15px', 'fontFamily': 'Inter, ui-sans-serif, sans-serif', 'lineColor': '#a5b4fc', 'primaryTextColor': '#e2e4ea', 'primaryColor': '#1e2330', 'primaryBorderColor': '#6366f1', 'secondaryColor': '#252b3b', 'tertiaryColor': '#181c26', 'background': '#0d0f14', 'clusterBkg': '#181c26', 'clusterBorder': '#374151', 'titleColor': '#e2e4ea'}}}%%
flowchart LR
    A([Claude Desktop])

    subgraph server["OpenSCAD MCP Server"]
        B["main.rs\nMCP handler"] --> C["openscad.rs\nfile + CLI"]
    end

    A -->|JSON-RPC / stdio| B
    C -->|write| D[(".scad / .stl\n~/.openscad-mcp/")]
    C -->|spawn| E([OpenSCAD CLI])
    E -->|PNG preview| B
        

Design decisions

Stdio transport Claude Desktop manages the process lifetime and owns the communication channel — no port binding, no daemon management, no firewall rules. The simplest possible integration.
Manager pattern OpenSCADManager owns the working directory and all file + subprocess operations. The MCP handler in main.rs only parses requests and delegates — no file logic leaks into the transport layer.
Local-only, zero auth The server runs on localhost and is controlled by process ownership. Adding authentication would add complexity with no security benefit — the threat model doesn't call for it.
Async throughout OpenSCAD renders can take seconds on complex geometry. Both file I/O (tokio::fs) and subprocess execution (tokio::process) are async, so the server stays responsive while waiting on the CLI.
Single working directory All SCAD sources, previews, and STL exports land in ~/.openscad-mcp/. One place to browse, one place to clean up — no file scattered across project directories.
Extensibility without restructuring Adding a new tool is three steps: add a method on OpenSCADManager, register it in list_tools(), handle it in the call_tool() match. No core changes needed.

Tech Stack

Core

  • Rust
  • rmcp SDK v0.16
  • Tokio (async runtime)

Process & I/O

  • tokio::process
  • tokio::fs
  • OpenSCAD CLI

Observability & Errors

  • tracing
  • tracing-subscriber
  • anyhow + thiserror

Protocol

  • Model Context Protocol
  • JSON-RPC over stdio

Quick Start

Prerequisites: Rust 1.70+ and OpenSCAD installed and on your PATH.

1 — Build

git clone https://github.com/N0t4R0b0t/openscad-mcp-server.git
cd openscad-mcp-server
cargo build --release
# binary → target/release/openscad-mcp-server

2 — Add to Claude Desktop config

{
  "mcpServers": {
    "openscad": {
      "command": "/path/to/openscad-mcp-server",
      "args": []
    }
  }
}

Config location: ~/.claude/claude_desktop_config.json on macOS/Linux, %APPDATA%\Claude\claude_desktop_config.json on Windows.

3 — Restart Claude Desktop and start designing

"Create a parametric phone stand — 100mm tall,
45-degree viewing angle, cable slot at the base."
Back to portfolio