Skip to main content
Glama
mcp-spatial-critic

mcp-spatial-critic

by vanovri

mcp-spatial-critic

PyPI tests license python

An MCP server (Model Context Protocol, stdio JSON-RPC 2.0) that gives headless CAD agents a deterministic 3D-printing critic. Zero dependencies — pure Python standard library, no numpy, no trimesh, no Blender, no OpenSCAD at runtime.

An LLM can write OpenSCAD that looks correct in a screenshot and still exports a mesh that is inside-out, floating 5 mm above the plate, split into three bodies, or full of zero-area slivers. mcp-spatial-critic fails the build before the printer does.

agent → generate STL → mcp-spatial-critic → {"approved": false, "errors": ["NON_MANIFOLD"]}
                                          → agent repairs → re-audit → {"approved": true}

Why agents need this

Text-only agents cannot see geometry. Vision models see a render, not a manifold. The failure modes below all render beautifully and all fail in a slicer:

Defect

What the render shows

What the slicer does

Non-manifold edges

Normal shade

Refuses to slice, or silently deletes shells

Floating base

Normal shade

Starts printing in mid-air

Disconnected shells

Normal shade

Prints 3 loose parts instead of one

Inverted normals

Normal shade (mostly)

Treats solid as void, prints nothing

Sub-nozzle features

Normal shade

Vase mode collapse / missing wall

Related MCP server: MakerSim

The five invariants

Every audit returns a critic_score from 0.0 to 10.0 and a list of critiques.

Check

Penalty

Error code

Every edge shared by exactly 2 triangles

−5.0

NON_MANIFOLD

Lowest Z sits on the build plate

−2.0

FLOATING_BASE

Exactly one connected shell

−2.0

MULTIPLE_SHELLS

Smallest bounding dimension ≥ min_wall_mm

−1.5

THIN_FEATURE

Positive signed volume (outward normals)

−1.0

INVERTED_OR_ZERO_VOLUME

No zero-area facets

−1.0

DEGENERATE_TRIANGLES

approved is true only when the error list is empty, the mesh is watertight and there is a single shell. The score is a ranking signal for repair loops; approved is the gate.

Install

# from GitHub — works today
pip install git+https://github.com/vanovri/mcp-spatial-critic

# or a checkout you can hack on
git clone https://github.com/vanovri/mcp-spatial-critic
cd mcp-spatial-critic
pip install -e .

Requires Python 3.10+. No third-party runtime packages.

Register the MCP server

Add this to your agent's MCP configuration (Claude Desktop claude_desktop_config.json, Claude Code .mcp.json, or any MCP-compatible client):

{
  "mcpServers": {
    "spatial-critic": {
      "command": "mcp-spatial-critic",
      "args": []
    }
  }
}

The server resolves relative paths against the directory it was launched from. Set MCP_SPATIAL_CRITIC_PRESETS to override where list_presets looks.

Tools

audit_stl

{
  "name": "audit_stl",
  "arguments": { "path": "build/bracket.stl", "min_wall_mm": 2.0 }
}

Response payload (also usable directly as a Python dict via audit_stl_file):

{
  "file": "bracket.stl",
  "path": "build/bracket.stl",
  "triangle_count": 12,
  "vertex_count": 8,
  "watertight": true,
  "non_manifold_edge_count": 0,
  "shell_count": 1,
  "bounding_box_mm": {
    "width_x": 20.0, "depth_y": 20.0, "height_z": 10.0,
    "min_z": 0.0, "max_z": 10.0
  },
  "volume_mm3": 4000.0,
  "degenerate_triangle_count": 0,
  "critic_score": 10.0,
  "approved": true,
  "critiques": [],
  "errors": []
}

isError is set on the MCP result whenever approved is false, so a tool-using agent sees the failure as a tool error rather than a success.

generate_reference_box

Writes a known-good watertight box and audits it. Use it as a control experiment when an agent claims its exporter is broken.

{ "out_path": "reference_box.stl", "width": 20, "depth": 20, "height": 10 }

list_presets

Lists the parametric presets bundled in presets/:

Preset

What it demonstrates

esp32_mount.scad

PCB standoff walls, snap lips, USB-C cutout, vent slots

m3_heatset_boss.scad

M3 brass insert seat with strengthening ribs

pagoda_roof_tier.py

Generator that splits >45° eaves into printable steps

python presets/pagoda_roof_tier.py > pagoda.scad
openscad -o pagoda.stl pagoda.scad

Talk to it without an agent

The transport is line-delimited JSON-RPC 2.0 on stdio, so you can drive it by hand:

printf '%s\n' \
  '{"jsonrpc":"2.0","id":1,"method":"initialize"}' \
  '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"generate_reference_box","arguments":{"out_path":"box.stl"}}}' \
  | mcp-spatial-critic

Library use

from mcp_spatial_critic import audit_stl_file, audit_stl_mesh, generate_watertight_box_stl

report = audit_stl_file("build/bracket.stl", min_wall_mm=1.6)
if not report["approved"]:
    for critique in report["critiques"]:
        print("FAIL:", critique)

# or audit an in-memory mesh
report = audit_stl_mesh(generate_watertight_box_stl(height=1.0))
assert "THIN_FEATURE" in report["errors"]

How it works

  • ASCII + binary STL parsers (core.py) — binary uses struct with a 50-byte stride; ASCII tolerates CRLF, tabs and malformed vertex lines.

  • Manifold test — canonicalised undirected edge keys (vertices rounded to 1e-5 mm) counted in a dict; any count ≠ 2 is a non-manifold edge.

  • Shell count — union-find with path compression over shared vertices.

  • Orientation — signed volume via the divergence theorem, Σ dot(v1, cross(v2, v3)) / 6.

  • Deterministic output — no timestamps, no random ordering; the same STL always produces the same bytes on the wire.

  • Server — handle_request() is a pure function (dict → dict | None), so the whole protocol is unit-testable without starting a process.

python -m unittest discover -s tests -v   # 40 tests

Known limitations (deliberate, tracked as issues)

  1. min_wall_mm is compared against the bounding box, not per-wall ray casts. A 40 × 40 × 20 mm hollow box with 0.4 mm walls passes this check. Real thin-wall detection needs slice-plane sampling — see GOOD_FIRST_ISSUES.md #3.

  2. Only STL is supported. 3MF and OBJ are open tasks.

  3. The critic diagnoses, it never repairs. Auto-repair belongs in the agent loop.

  4. Binary STL headers that begin with solid are disambiguated by looking for the facet keyword in the first 512 bytes. A pathological header could fool it.

  5. No build-volume check yet (the bbox is reported, the comparison is not).

Contributing

See GOOD_FIRST_ISSUES.md for scoped, test-covered starter tasks. Every PR needs a test that fails before the fix. Run the suite with python -m unittest discover -s tests -v.

License

MIT — see LICENSE.

Available Tools

3 tools
audit_stlA

Audit a STL mesh for watertightness/manifoldness, build-plate grounding, disconnected shells, inverted normals and thin features.

Inputs: path (required), min_wall_mm, min_z_tolerance_mm.

generate_reference_boxC

Write a known-watertight reference box and audit it.

Inputs: depth, width, height, out_path.

list_presetsA

List the bundled parametric CAD presets (OpenSCAD / generator).

Inputs: no named parameters.

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    B3.2/5.0

    Scored across 3 tools

    Disambiguation5/5

    Each tool has a clearly distinct purpose: auditing an existing STL, generating and auditing a reference box, and listing presets. The generate_reference_box tool's inclusion of an audit step does not blur its boundary because it is explicitly a fixture-creation operation.

    Naming Consistency5/5

    All three names follow a consistent snake_case verb_noun pattern: audit_stl, generate_reference_box, list_presets. The convention is predictable and readable.

    Tool Count4/5

    Three tools is on the low end but fits the focused purpose of an STL audit critic. Each tool earns its place, though the surface is somewhat thin for anything beyond basic auditing.

    Completeness3/5

    The core audit operation is covered, but the surface has notable dead ends: presets can be listed but not run or inspected, and there is no repair or re-audit workflow for failed meshes. Agents can work around this for simple audits but will hit gaps in a full CAD validation lifecycle.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      B
      maintenance
      Enables an LLM to design parametric 3D parts in pure NumPy and verify they are actually printable before exporting them. Provides topology checks (watertightness, genus, shell count, wall thickness), self-rendered views, and gated STL/OBJ export that refuses broken solids.
      7
      MIT
    • A
      license
      Not graded
      quality
      B
      maintenance
      Experimental load-path analysis for 3D-printed STL parts, with stress and movement comparisons across CAD revisions, PNG captures, visual reviews, and persistent human-guided design sessions. Runs locally through a stdio MCP server.
      MIT
    • A
      license
      Not graded
      quality
      B
      maintenance
      Lets an AI assistant check and repair STL/3MF meshes stored on your own computer, reporting holes, flipped faces, inside-out shells, non-manifold edges and duplicate triangles and writing a fixed copy beside the original. Everything runs locally, so the files are never uploaded and the original is never overwritten.
      10 npm
      MIT
    • A
      license
      Not graded
      quality
      C
      maintenance
      Enables AI engineering agents to deterministically validate 3D mesh invariants (C1-C10), verify SHA-256 content hashes, and generate fail-closed conformance reports.
      1
      MIT