An MCP server that lets AI agents build, edit, render, and export real 3D models from primitives and boolean CSG. Headless, GPU-free.
Chisel provides 15 tools for 3D CSG modeling with explicit JSON Schema definitions visible in src/lib/scene/tools.ts. Strengths: all tools have descriptions (10 - 160 chars, median ~80 chars), all have documented input schemas with type constraints, good use of enums (axis, format), and clear geometric parameter descriptions (e.g., 'Box dimensions [w,h,d]', 'Euler rotation in DEGREES [x,y,z]'). Weaknesses: (1) tool naming is inconsistent, add_box/add_sphere use imperative 'add_*', but transform/union/subtract lack clear action prefixes. 'intersect' could be 'compute_intersection' for clarity. (2) descriptions are minimal (10 - 30 chars for many tools like 'Add a sphere primitive.'), missing context on when/why to use each tool, no dependency hints, and no output schema documentation. (3) output schemas are completely undocumented in code comments, LLMs must infer what render() returns or what structure union() produces. (4) error handling and recovery guidance absent, no indication of what goes wrong, what to do on failure, or whether operations are retryable. (5) select and finish tools appear in TOOLS array but are filtered out at server startup (line 'TOOLS.filter(...!=["finish", "select"]'), creating confusion about which 15 tools actually exist. (6) session parameter present on all tools but never explained in function descriptions, LLMs cannot infer that sessions enable parallel model management. (7) no permission gates, no audit trails, no rate limiting despite WRITE and DESTRUCTIVE risk annotations.
Add a box primitive. Returns its object id (objN).
Add a cone primitive (apex +Y, base -Y, before rotation).
Add a cylinder primitive (axis along Y before rotation).
Add a sphere primitive.
Delete an object.
Export the current model to a glTF (.glb) or Wavefront (.obj) file on disk. Returns the file path.
Return the current model's scene graph as text (every object, its shape, and its transform).
Output schemas completely undocumented. add_box returns 'object id (objN)' mentioned in description only, no formal schema showing the response structure. render() returns 'a 2x2 grid of PNG' but the actual response format (object with base64 field? file path?) is invisible. export_model mentions 'base64-encoded' but no output schema explains the return type. LLMs cannot plan downstream tool calls without knowing which fields to extract.
No error handling or recovery guidance. Tools marked as WRITE and DESTRUCTIVE (union, subtract, delete, reset) provide no guidance on what happens if operation fails, whether it's retryable, or how to recover. No indication of validation errors (e.g., invalid object id, invalid color format). LLMs cannot self-correct on failure.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 60 | 2026-07-28+ | v2 |
Boolean intersect: keep only the overlap of a and b. Consumes both.
Duplicate an object reflected across a plane. Use for symmetry (build one side, mirror it).
Render the current model and return a PNG image: a 2x2 grid of FRONT (top-left), SIDE (top-right), TOP (bottom-left), ISO (bottom-right). Call this to SEE the model before deciding what to change.
Clear the current model session back to an empty scene.
Recolor an object.
Boolean subtract: cut b out of a. Consumes both, yields new object.
Set or offset an object's position/rotation/scale.
Boolean union: merge a and b into one object. Consumes both.
Session parameter present on ALL tools but never documented in tool descriptions. Description text says nothing about 'session', only the JSON Schema lists it. LLMs cannot infer that sessions enable parallel model management without explicit documentation. This is a critical affordance gap.
Inconsistent tool naming. Primitive creation uses 'add_*' (add_box, add_sphere), but boolean ops use bare verbs (union, subtract, intersect). 'intersect' is ambiguous, does it return the overlap, or does it intersect in place? Recommend: compute_intersection or boolean_intersect for clarity. Contradicts pattern:tool verb_noun guidance.
Minimal, under-20-char descriptions on primitive creation tools. 'Add a sphere primitive.' does not explain when to use add_sphere vs add_cylinder, what constraints apply, or context on geometric modeling. Baseline for A+ tools: 50 - 200 chars. Current: 10 - 30 chars on most tools. Violates pattern:tool-description guidance.
Parameter constraints not fully documented. Color parameter accepts 'Palette name or #rrggbb hex' but no enum of valid palette names provided, and no validation guidance (e.g., must match [0-9a-fA-F]{6}). LLMs will guess on palette names, leading to invalid calls. Should provide enum of valid colors or explicit format pattern.
Tool filtering inconsistency. TOOLS array in src/lib/scene/tools.ts includes 'select' and 'finish', but server.ts filters them out before registration (line: TOOLS.filter(...!=["finish", "select"]). This creates confusion: are these 15 or 17 tools? Documentation claims 15 but source shows 17 before filtering. The filtering logic should be explicit in source comments.
No confirmation or dry-run pattern for destructive operations. delete and reset are irreversible but provide no confirmation step or dry-run capability. Pattern:confirmation-request requires that agents have a chance to verify before catastrophic operations. Recommend adding 'confirm' boolean parameter or a separate 'preview_delete' tool.
No tool annotations for risk classification. JSON Schema uses custom 'Risk' field (WRITE, DESTRUCTIVE, READ_ONLY) outside MCP standard. Modern MCP spec (2026-07-28) defines readOnlyHint, destructiveHint, idempotentHint in tool metadata. Recommend migrating to standard MCP tool annotations for spec compliance.