Skip to main content
Glama
mcp-printable

mcp-printable

Printable

MCP server for AI-driven 3D modeling, optimized for FDM-printable geometry.

Connect any MCP-capable agent (Claude Code, Goose, Cursor, Codex, Cline, etc.) to a 3D modeling backend and get tools tuned for the design loop that actually produces parts you can print.

Why this exists

LLMs are good at writing geometry code but bad at the things that make a part actually printable: clearances on moving joints, overhangs, bridging, units, watertight meshes. Printable encodes those constraints into both the tool surface (typed booleans, printability checks, clearance sweeps, cross-sections) and the prose rules the agent reads (cardinal print-path rule, FDM clearance values, mechanism patterns).

The result: you can ask any MCP-aware agent "build me a hinge with 5mm barrel and 20×15mm flanges" and get a part that comes off the bed working.

Related MCP server: 3d-printagent

Backends

  • Blender (blender_* tools, 25 of them). Full design loop with rendering, cross-sections, printability validation. Requires Blender 3.6+ installed and the included addon enabled.

  • OpenSCAD (scad_* tools, 5 of them, see docs/openscad/README.md). Code-first parametric backend. No app, no addon — shells out to the openscad CLI and uses trimesh for mesh validation. Requires OpenSCAD installed.

Cross-backend handoff happens via STL — both backends import and export it.

Architecture

Agent  <--stdio/MCP-->  server.py  <--TCP :9876-->  Blender addon
                              \
                               +----shell-out------>  openscad CLI + trimesh
  • server.py — FastMCP server. Exposes the tool surface and embeds the always-on rules in the MCP instructions field, with pointers into docs/ for deeper guidance.

  • addon/ — Blender addon. TCP server on 127.0.0.1:9876. Commands run on Blender's main thread via bpy.app.timers.

  • docs/ — agent-agnostic prose guidance: print-in-place rules, design loop, image displacement. Also exposed as MCP resources under printable://… URIs (see Documents below) so any resource-aware MCP client can pull them via the protocol — no filesystem access required.

  • .claude/skills/ — thin Claude shims (description-triggered loading) that point into docs/. Other agents use resources or filesystem.

  • evals/ — policy-based regression tests that verify agents actually follow the rules. See evals/README.md.

Status

v0.1.x — alpha. Blender backend is feature-complete and dogfooded against real prints; OpenSCAD backend covers the parametric workflow but has fewer validation tools. API is stable enough to use but may shift before 1.0.

Requirements

  • Python 3.10+ for the MCP server.

  • Blender 3.6+ if you're using the Blender backend (the bundled addon needs to be installed once and enabled in Blender's Preferences).

  • OpenSCAD CLI if you're using the SCAD backend (auto-discovered on PATH and in the standard install locations on Windows / macOS / Linux).

  • An image-capable agent model. The visual-feedback tools (blender_get_screenshot, blender_render_tiled, blender_render_turntable, blender_cross_section*, blender_render_printability_heatmap, blender_render_with_dimensions, blender_render_before_after, scad_render_views, scad_cross_section) return base64-encoded PNGs that the agent has to actually see to use them. Text-only models will still get tool results but can't interpret the rendered geometry — the design loop relies on the agent looking at renders and cross-sections to verify what it's built. Examples that work well: Claude Sonnet 4.x+, GPT-4o/5, Gemini 2.x Pro/Flash. Text-only models will technically run but won't catch shape-level mistakes.

Setup

Install from PyPI

pip install mcp-printable       # or: uv pip install mcp-printable
printable-install-addon         # copies the bundled addon into Blender's addon dir

Then in Blender: Preferences → Add-ons → enable "Printable Blender Bridge".

Install from source

git clone https://github.com/AaronGoldsmith/mcp-printable
cd mcp-printable
uv sync                         # or: pip install .
python install.py               # equivalent to printable-install-addon
IMPORTANT

Run the install step from a terminal —NOT Blender's "Install from Disk" dialog. See SETUP.md for why and other gotchas.

Wire into your agent

For Claude Code (~/.claude.json or project .mcp.json), pick one of two options.

Option A — uvx (recommended; no prior install needed):

{
  "mcpServers": {
    "printable": {
      "type": "stdio",
      "command": "uvx",
      "args": ["--from", "mcp-printable", "printable"]
    }
  }
}

uvx will pull mcp-printable from PyPI on first run and cache it. To pick up new releases later, run uvx --refresh --from mcp-printable printable once or pin a version with mcp-printable@0.1.2.

Option B — global pip install (simpler if you already have mcp-printable on PATH):

{
  "mcpServers": {
    "printable": {
      "command": "printable"
    }
  }
}

Requires pip install mcp-printable to have put printable on your PATH first.

For other agents (Goose, Cursor, etc.) — same command, wrapped in your agent's MCP server configuration.

Agent skills (optional)

This repo bundles four Claude Code skills under .claude/skills/ — short shims that point at the same docs/ content the MCP exposes as resources. Claude Code auto-discovers them when you launch it in the repo:

git clone https://github.com/AaronGoldsmith/mcp-printable
cd mcp-printable && claude

The 4 skills:

  • print-in-place — design rules for moving-parts mechanisms (hinges, ball-sockets, snap fits)

  • blender-design-loop — plan→build→verify→validate→export workflow

  • image-displacement — turn a 2D image into 3D printable relief

  • blender-app — launch / restart / multi-instance Blender setup

For Claude Code, copy a skill into ~/.claude/skills/ to make it available across all projects. For other agents (Codex, Cursor, Goose, ...) — see AGENTS.md, which links each skill into the equivalent location for your agent and explains the MCP-resource fallback for agents that don't load project skills.

Tool families

Blender (23 tools)

Scene — blender_get_scene_info, blender_get_object_info, blender_clear_scene, blender_restore_checkpoint (roll back to the auto-saved checkpoint after a destructive mistake), blender_rename_object

Code — blender_execute_code (arbitrary bpy/bmesh; auto-checkpoints), blender_boolean (typed UNION/DIFFERENCE/INTERSECT — prefer this over execute_code)

Visual feedback — blender_get_screenshot, blender_render_tiled, blender_render_turntable, blender_cross_section, blender_cross_section_gallery, blender_render_printability_heatmap, blender_render_with_dimensions, blender_render_before_after

Print validation — blender_validate (one tool for HEALTH / OVERHANGS / THIN_WALLS / CLEARANCE checks; checks=['ALL'] runs the full suite — replaces the former mesh_health / check_overhangs / check_thin_walls / full_printability_check tools), blender_check_clearance, blender_check_clearance_sweep, blender_check_intersection, blender_check_retention

Export — blender_export_stl, blender_import_stl, blender_save_blend

OpenSCAD (5 tools)

scad_compile, scad_render_views, scad_cross_section, scad_validate_printability, scad_import_stl. Shells out to the openscad CLI; uses trimesh for mesh validation. Full docs: docs/openscad/README.md.

The Design Loop

Always-on rules embedded in the MCP server's instructions field — every agent that connects sees them automatically. Summary:

  1. Plan. Compute coordinates and dimensions in one execute_code call that PRINTS them. Verify the math BEFORE creating geometry.

  2. Build. 1–3 operations per execute_code, then blender_validate(checks=['HEALTH']).

  3. Verify. Renders for shape, cross-sections for internal truth.

  4. Validate. blender_check_clearance_sweep for any joint. blender_validate(checks=['ALL']) before export.

  5. Export. blender_export_stl (no args = bundle all parts).

Full doc: docs/blender/design-loop.md.

For mechanism design (hinges, ball-sockets, snap fits, articulated chains): docs/design/print-in-place.md. This is backend-agnostic — same rules apply if you're using OpenSCAD.

Documents

Every doc below is served two ways:

  1. As an MCP resource under printable://… — the preferred path. Resource-aware clients fetch via resources/read, get the same content the maintainer ships, and don't need filesystem access to the project. Resources travel with the MCP server itself, so a pip install mcp-printable user has the docs even without cloning the repo.

  2. As a file in docs/ — fallback for filesystem-based clients, and for humans browsing the repo.

If you're writing an MCP client, prefer the URI. The filesystem path is documented mainly so a human can click through from this README.

URI

File

Purpose

printable://design/print-in-place

docs/design/print-in-place.md

FDM mechanism design: cardinal print-path rule, clearances, patterns, validation checklist (backend-agnostic)

printable://blender/design-loop

docs/blender/design-loop.md

Plan→build→verify→validate→export workflow, boolean rules, failure modes

printable://blender/image-displacement

docs/blender/image-displacement.md

2D image → printable 3D relief

printable://blender/blender-app

docs/blender/blender-app.md

Launch / restart / multi-instance setup

printable://openscad/backend

docs/openscad/README.md

OpenSCAD backend setup, tool reference, validator details, cross-backend handoff

docs/
├── design/                          # backend-agnostic design rules
│   └── print-in-place.md
├── blender/                         # Blender-specific
│   ├── design-loop.md
│   ├── image-displacement.md
│   └── blender-app.md
└── openscad/                        # OpenSCAD-specific
    └── README.md

Testing

python -m pytest tests/ -v          # unit tests, no Blender required
python evals/runner.py              # policy-based regression evals (see evals/README.md)

Unit tests cover TCP protocol framing, image compositing (PIL), MCP tool registration. The eval suite checks that agents using the MCP actually follow the always-on rules (e.g. clear scene first, prefer blender_boolean, no monolithic execute_code blocks) — procedural checks from the tool trace, plus LLM-judged outcome policies for things like "moving parts have a continuous print path to the bed."

Roadmap

Things on the list, not yet shipped:

  • Validated parameter recipes — turnkey parameter sets for common print-in-place mechanisms (wheel-on-axle, flip-tile, ball-and-socket, snap fit) so an agent can ask for "a toy car wheel" and get a known-good geometry without re-solving the clearance + retention math each time. Earlier drafts existed but weren't dialed in enough to ship as authoritative; new ones will land once they're validated against real prints.

  • Blender app-lifecycle tools (blender_launch / blender_status / blender_kill) — let the agent spin Blender up itself instead of needing the user to start it first.

  • Second OpenSCAD parity pass — match Blender's clearance-sweep / retention / thin-wall checks on the SCAD side.

Contributing

The interesting design surface is in docs/. New always-on rules belong in docs/design/ (backend-agnostic) or docs/blender/ / docs/openscad/ (backend-specific). If a rule should be enforced, also add a policy file under evals/policies/ and a scenario under evals/scenarios/ so the eval runner picks it up.

License

MIT — see LICENSE.

Available Tools

29 tools
blender_booleanA
Destructive

Boolean op on two meshes with built-in connectivity + manifold checks. Always prefer this over raw modifiers in execute_code.

operation: DIFFERENCE | UNION | INTERSECT. solver: EXACT (reliable) | FAST. use_self (EXACT only): classify self-intersecting operands via winding numbers. Set True when an operand contains multiple overlapping shells (multi-shell meshes) — without it the EXACT solver can silently annihilate the target (an ANNIHILATION warning in the result flags this). Slower; default False. use_hole_tolerant (EXACT only): better results when operands have holes (non-watertight geometry). Slower; default False. Returns face counts, connected components, warnings. A WARNING means the boolean may have silently failed — inspect the numbers and re-run.

Inputs: cutter (required), target (required), solver, use_self, +3 more. Returns: result

blender_check_clearanceB
Read-onlyIdempotent

Minimum gap between two objects. Default 0.3mm is typical FDM print-in-place clearance — below this, parts fuse.

Inputs: object_a (required), object_b (required), min_clearance_mm. Returns: result

blender_check_clearance_sweepA
Read-onlyIdempotent

Rotate inner_object through 360° and check clearance at each step. MANDATORY for any joint, hinge, or articulating mechanism.

A hinge that looks fine at 0° may collide at 90°. Returns worst-case clearance and the angle where it occurs. passes=False → the joint WILL fuse during printing.

Inputs: inner_object (required), outer_object (required), axis, steps, +1 more. Returns: result

blender_check_intersectionA
Read-onlyIdempotent

Check if two meshes physically overlap. Use after assembly — separate parts should NEVER volumetrically overlap (would mean a boolean went wrong, or parts were placed too close).

Distinct from clearance (which measures distance between non-touching objects). Returns contact_type: NONE | SURFACE_CONTACT (coincident faces, expected for flush-fit assemblies) | VOLUMETRIC_OVERLAP (parts share volume and will fuse), plus overlap_volume_mm3, contact_area_mm2 (half the intersection mesh's surface area — the contact patch), mean_penetration_um (overlap volume spread over the contact area — micron-scale means flush contact / float dust, tens of microns or more means real penetration; use it to judge borderline cases yourself), and the raw face-pair count.

Inputs: object_a (required), object_b (required). Returns: result

blender_check_retentionA
Read-onlyIdempotent

Verify a moving part is captive by translating it displacement mm in direction and checking intersection with static_objects. Returns CAPTIVE or FREE.

direction: '+X'/'-X'/'+Y'/'-Y'/'+Z'/'-Z'. Use for: car body on axles, ball in socket, hinge pin in barrel.

Inputs: moving_object (required), static_objects (required), direction, displacement. Returns: result

blender_clear_sceneA
DestructiveIdempotent

Remove all objects from the scene. Refuses to wipe a non-empty scene unless force=True.

Default behavior protects in-progress user work — if the scene already has objects, this tool returns an error listing them and asks the agent to confirm intent. Pass force=True to override (for genuine fresh-build scenarios). Always sets units to mm regardless.

Inputs: force. Returns: result

blender_cross_sectionA
Read-onlyIdempotent

Cut and render the exposed internal face. Use to verify internal geometry that renders can't show: pin holes, wall thickness, knuckle interleave, clearance gaps.

percent: 0-100, position along the chosen axis (50 = middle). object_names: cut multiple objects with the same plane and render them together. Essential for verifying chain joints, ball-in-socket captivity, or any pair where parts wrap around each other.

Provide exactly one of object_name OR object_names — sending both raises ValueError to avoid silent precedence bugs.

Inputs: axis, percent, object_name, object_names.

blender_execute_codeA
Destructive

Run Python in Blender (bpy, bmesh, mathutils, math available). Set __result__ to return a value. Keep under ~20 lines.

For boolean ops use blender_boolean instead — it's safer and validates the result. NEVER use bpy.ops.object.join() (creates internal faces). After any geometry change call blender_validate(checks=['HEALTH']) to verify watertight + manifold.

Inputs: code (required). Returns: result

blender_export_stlA
Idempotent

Export mesh(es) to a single STL for 3D printing. Warns about non-manifold edges.

With no object args: exports ALL mesh objects bundled into one STL (most common for printing). Use object_name for one part, object_names=[...] for a specific bundle. Relative paths resolve against the MCP server's cwd, not Blender's (which is its install dir, read-only on Windows).

Inputs: path (required), binary, object_name, object_names. Returns: result

blender_get_object_infoA
Read-onlyIdempotent

Get detailed info about a specific object: dimensions, mesh stats, modifiers, materials, manifold check.

object_name: the object to inspect. (name is a deprecated alias kept so older callers keep working; every other single-object tool uses object_name.)

Inputs: name, object_name. Returns: result

blender_get_scene_infoA
Read-onlyIdempotent

Get a summary of all objects in the Blender scene: names, types, dimensions, vertex counts.

Inputs: no named parameters. Returns: result

blender_get_screenshotA
Read-onlyIdempotent

Single screenshot from a custom camera angle. Use when render_tiled's 4 fixed views miss what you need.

elevation: deg above horizontal (0=side, 90=top, negative=below). azimuth: deg rotation (0=front, 90=right, 180=back). focus_object + isolate: frame and isolate one part for a clean detail view.

Inputs: zoom, width, height, azimuth, +3 more.

blender_import_stlB

Import an STL file into the scene.

Relative paths are resolved against the MCP server's working directory.

Inputs: path (required). Returns: result

blender_rename_objectA
Idempotent

Rename an object (e.g., 'Cylinder.001' -> 'hinge_barrel').

Inputs: new_name (required), old_name (required). Returns: result

blender_render_before_afterA
Destructive

Capture before/after screenshots around a modeling operation.

Provide the bpy code to execute between captures. Returns a side-by-side comparison.

Inputs: code (required).

blender_render_printability_heatmapA
Idempotent

Render the object with faces colored by printability issues.

Red = overhang, Yellow = thin wall, Green = OK. Returns a multi-angle tiled image plus issue counts.

Inputs: object_name (required), min_wall_mm, overhang_angle.

blender_render_tiledA
Read-onlyIdempotent

4-angle labeled grid render — your primary feedback tool after every modeling step.

Default views: iso/front/right/top. Available: iso, front, back, right, left, top. Use focus_object (+isolate) to zoom into a specific part. Follow up with cross_section_gallery if internal geometry needs verification.

Inputs: zoom, angles, isolate, focus_object.

blender_render_turntableA
Read-onlyIdempotent

N-angle turntable around one object. Use for cylindrical geometry (barrels, pins) where 4 fixed angles miss details.

steps=8 → every 45°, steps=12 → every 30°. elevation in degrees (negative=below).

Inputs: object_name (required), zoom, steps, isolate, +1 more.

blender_render_with_dimensionsA
Read-onlyIdempotent

Render the scene with bounding box dimension data for each object.

Returns an isometric render plus dimension measurements for each object.

Inputs: object_names.

blender_restore_checkpointA
DestructiveIdempotent

Restore the scene from the auto-saved checkpoint — the undo button for a destroyed mesh.

A checkpoint is saved automatically before every blender_boolean and blender_execute_code call, so this rolls back to the state just before the most recent mutating operation. Replaces ALL current scene objects. Use immediately after a DEGENERATE RESULT warning or a botched edit — a subsequent mutating call overwrites the checkpoint with the broken state.

Inputs: no named parameters. Returns: result

blender_save_blendA
Idempotent

Save the current scene as a .blend file.

If path is omitted, saves to the current file or a temp location. Relative paths are resolved against the MCP server's working directory.

Inputs: path. Returns: result

blender_validateA
Read-onlyIdempotent

Run specified printability checks on a mesh. Valid checks: 'ALL', 'HEALTH', 'OVERHANGS', 'THIN_WALLS', 'CLEARANCE'.

Replaces individual mesh_health, overhang, and thin_wall checks. Use checks=['ALL'] to run the full printability suite before STL export. Set clearance_partners to check clearance against named neighbors. Per-face issue lists are capped at 10 exemplars; pass verbose=True for the full lists (can be very large on dense meshes).

Inputs: object_name (required), checks, verbose, min_wall_mm, +3 more. Returns: result

blender_version_infoA
Read-onlyIdempotent

Report the MCP server version vs. the installed Blender addon version.

The server auto-updates from PyPI, but the addon is a copy inside Blender's addons dir that only updates via 'python install.py' + Blender restart — use this to diagnose stale-addon behavior. Addons older than 0.2.3 don't report a version and show as unknown.

Inputs: no named parameters. Returns: result

scad_compileA
Idempotent

Compile OpenSCAD code to STL via CGAL. Always follow with scad_validate_printability on the result.

output_path: relative paths resolve against MCP server cwd (so "cube.stl" lands in your project dir, not Blender's). Omit to write to a tempdir.

Inputs: code (required), timeout, output_path. Returns: result

scad_cross_sectionA
Read-onlyIdempotent

Slice the model with a thin slab and render the cut. The only reliable way to verify internal geometry (clearances, hollows, joints).

percent: 0-100 along the chosen axis (mapped onto the model's actual bounds). slab_thickness in model units. Compiles the code to STL first, so expect CGAL render time on heavy models.

Inputs: code (required), axis, size, view, +2 more.

scad_import_stlA
Read-onlyIdempotent

Return an OpenSCAD snippet that imports the given STL — for Blender→SCAD handoff or further parametric modification.

Returned snippet includes a NOTE about the --render-mode path caveat.

Inputs: stl_path (required), convexity. Returns: result

scad_render_viewsA
Read-onlyIdempotent

Render multiple labeled views of an OpenSCAD model into a grid image.

Default views: iso, front, right, top. Set preview=False for CGAL- rendered final views (slower).

Inputs: code (required), size, views, preview.

scad_validate_printabilityA
Read-onlyIdempotent

Watertight / manifold / volume / overhang checks on an STL via trimesh. Run after every scad_compile.

PASS/WARN/FAIL verdict + structured report.

Inputs: stl_path (required), min_volume_mm3, max_overhang_deg. Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.9/5.0

    Scored across 29 tools

    Disambiguation4/5

    Most tools target distinct operations, but rendering tools (screenshot vs tiled vs turntable) and cross-section tools (single vs gallery) have overlapping purposes that could confuse agents. The descriptions mitigate ambiguity but don't fully eliminate it.

    Naming Consistency5/5

    All tools follow a consistent pattern: engine prefix (blender_/scad_) + verb + noun(s), all lowercase with underscores. Verbs vary (import, get, clear, render, check, validate, export, etc.) but the naming style is uniform and predictable.

    Tool Count2/5

    With 29 tools, the set exceeds the 25+ threshold for 'too many.' While the two-engine scope (Blender and OpenSCAD) partially justifies the count, the sheer number is heavy and risks overwhelming agents.

    Completeness5/5

    The toolset covers the full 3D-printing workflow: import, geometry creation/editing (via execute_code and boolean), inspection (renders, cross-sections), printability validation (overhang, thin walls, clearance, intersection, retention), and export (STL, BLEND, SCAD). No critical gaps are apparent.

    Maintenance

    ActivityInactive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      Enables LLMs to create and manipulate 3D models using OpenSCAD through MCP tools for code-based modeling, preview, and export.
      1
      MIT
    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables AI agents to manage multiple 3D printers via MCP, including monitoring temperatures and progress, uploading and slicing models, controlling prints, and viewing cameras.
      8 npm
      MIT
    • F
      license
      Not graded
      quality
      A
      maintenance
      Enables AI agents to inspect and control a live Blender session through MCP tools that create, modify, and delete objects, apply materials, render images, execute Python, and pull PolyHaven assets over a local TCP add-on. It also exposes a provider-agnostic LLM layer that can be pointed at Ollama, LM Studio, llama.cpp, OpenAI-compatible, or Azure endpoints and switched at runtime.
      -