Skip to main content
Glama

compose_part_from_primitives

Build exact, functional 3D parts by combining geometric primitives with boolean union, difference, and intersection operations, then export a print-ready STL centered on the bed.

Instructions

Build a functional part by composing geometric primitives with booleans.

        The **CAD-aware generation path** -- instead of asking text-to-mesh AI
        to guess at geometry, describe parts as a tree of primitives combined
        with boolean operations. Produces exact, deterministic, functional parts.

        **SAFETY DEFAULT (changed 2026-04-15):** ``center_on_bed=True`` is the
        default.  OpenSCAD primitives are natively centered on the model origin
        (``cylinder(h,r)`` produces geometry centered on X/Y = (0,0), which
        means half the geometry lives at NEGATIVE X/Y).  Sending such an STL
        to most FDM printers (Bambu, Prusa, Ender, Creality) — whose bed
        origin is the front-left corner — causes the nozzle to drive off-bed
        into the purge/wipe assembly on layer 1.  This happened once on a
        Bambu A1 (incident #0, 2026-04-15, nearly damaged the printer).

        With ``center_on_bed=True`` the output STL is translated so it sits
        centered on the build plate and its lowest point touches z=0.  Set
        ``center_on_bed=False`` only if your downstream flow expects
        origin-centered geometry (e.g. further CAD composition).

        **Operation format** -- each item is either a primitive or boolean:

        Primitive: ``{"type": "primitive", "shape": "<shape>",
        "params": {...}, "translate": [x,y,z], "rotate": [rx,ry,rz]}``

        Boolean: ``{"type": "boolean", "operation": "union|difference|intersection",
        "children": [op1, op2, ...]}``

        **Primitive shapes and params:**
        - cube: ``{"size": [x,y,z]}`` or ``{"size": scalar}``
        - cylinder: ``{"h": height, "r": radius}`` or ``{"h", "r1", "r2"}``
        - sphere: ``{"r": radius}``
        - cone: ``{"h": height, "r1": bottom_r, "r2": top_r}``
        - torus: ``{"major_r": ring_radius, "minor_r": tube_radius}``
        - wedge: ``{"width": w, "depth": d, "height": h}``
        - hex_prism: ``{"r": radius, "h": height}``  -- hexagonal (for nuts)
        - text: ``{"text": "string", "size": 10, "depth": 2}``
        - rounded_cube: ``{"size": [x,y,z], "radius": 1}``
        - pipe: ``{"h": height, "outer_r": 10, "inner_r": 8}``

        Requires OpenSCAD installed on the system.

        :param brief_id: The saved goal's id from ``design_session``, so this make
            is recorded against the goal and checked against it. Empty when
            there is no goal.
        :param operations: The part as a tree of operation dicts.  A
            primitive is ``{"type": "primitive", "shape": ..., "params": {...}}``
            with optional ``"translate": [x,y,z]`` and ``"rotate": [rx,ry,rz]``;
            shape is one of ``cube``, ``cylinder``, ``sphere``, ``cone``,
            ``torus``, ``wedge``, ``hex_prism``, ``text``, ``rounded_cube``,
            ``pipe``.  A boolean is ``{"type": "boolean", "children": [...]}``
            with ``"operation"`` ``union``, ``difference`` or ``intersection``.
            Shape params are listed in the tool description.
        :param output_path: Output path (defaults to temp file).
        :param center_on_bed: Translate output to bed-center (default True).
        :param bed_x_mm: Build plate X dimension for centering (default 256).
        :param bed_y_mm: Build plate Y dimension for centering (default 256).
        :param printer_id: Optional printer: a supported model id, or the
            name of a printer set up in Kiln.  When provided, its recorded
            bed size replaces the explicit dimensions.
        :returns: Dict with result path, SCAD code, triangle count, and
            (if centered) ``bed_centered=True`` + applied translation.

INLINE 3D STAGE: on success this tool opens Kiln's interactive 3D stage — an inline viewer panel the user can orbit, zoom, and turn over — in hosts that render MCP Apps panels (Kiln's hosted connection attaches a browser stage link for hosts that don't). Oversized meshes are decimated automatically for the stage; the PNG preview is the floor, not the whole experience.

MAKE DOORS: design_session, Kiln's front door for making an object, is not installed here (signed in to Kiln it runs on Kiln's servers). On this install compile_scad IS the make → preview → iterate loop: make it, show the preview, iterate.

Tool call template

Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {
      "operations": "<operations>"
    },
    "name": "compose_part_from_primitives"
  }
}

Input Schema

NameRequiredDescriptionDefault
bed_x_mmNoBuild plate X dimension for centering (default 256). Default: 256.0.
bed_y_mmNoBuild plate Y dimension for centering (default 256). Default: 256.0.
brief_idNoThe saved goal's id from ``design_session``, so this make is recorded against the goal and checked against it. Empty when there is no goal. Default: "".
operationsYesThe part as a tree of operation dicts. A primitive is ``{"type": "primitive", "shape": ..., "params": {...}}`` with optional ``"translate": [x,y,z]`` and ``"rotate": [rx,ry,rz]``; shape is one of ``cube``, ``cylinder``, ``sphere``, ``cone``, ``torus``, ``wedge``, ``hex_prism``, ``text``, ``rounded_cube``, ``pipe``. A boolean is ``{"type": "boolean", "children": [...]}`` with ``"operation"`` ``union``, ``difference`` or ``intersection``. Shape params are listed in the tool description.
printer_idNoOptional printer: a supported model id, or the name of a printer set up in Kiln. When provided, its recorded bed size replaces the explicit dimensions. Default: "".
output_pathNoOutput path (defaults to temp file). Default: "".
center_on_bedNoTranslate output to bed-center (default True). Default: true.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed7 schema fields changedv1.5.1
    • changedInput schema / properties / bed_x_mm / description
      Previous value: -"Default: 256.0."New value: +"Build plate X dimension for centering (default 256). Default: 256.0."
    • changedInput schema / properties / bed_y_mm / description
      Previous value: -"Default: 256.0."New value: +"Build plate Y dimension for centering (default 256). Default: 256.0."
    • changedInput schema / properties / brief_id / description
      Previous value: -"Default: \"\"."New value: +"The saved goal's id from ``design_session``, so this make is recorded against the goal and checked against it. Empty when there is no goal. Default: \"\"."
    • changedInput schema / properties / center_on_bed / description
      Previous value: -"Default: true."New value: +"Translate output to bed-center (default True). Default: true."
    • addedInput schema / properties / operations / description
      Added value: +"The part as a tree of operation dicts.  A primitive is ``{\"type\": \"primitive\", \"shape\": ..., \"params\": {...}}`` with optional ``\"translate\": [x,y,z]`` and ``\"rotate\": [rx,ry,rz]``; shape is one of ``cube``, ``cylinder``, ``sphere``, ``cone``, ``torus``, ``wedge``, ``hex_prism``, ``text``, ``rounded_cube``, ``pipe``.  A boolean is ``{\"type\": \"boolean\", \"children\": [...]}`` with ``\"operation\"`` ``union``, ``difference`` or ``intersection``. Shape params are listed in the tool description."
    • changedInput schema / properties / output_path / description
      Previous value: -"Default: \"\"."New value: +"Output path (defaults to temp file). Default: \"\"."
    • changedInput schema / properties / printer_id / description
      Previous value: -"Default: \"\"."New value: +"Optional printer: a supported model id, or the name of a printer set up in Kiln.  When provided, its recorded bed size replaces the explicit dimensions. Default: \"\"."
  2. Changed11 schema fields changedv1.5.0
    • removedInput schema / properties / bed_x_mm / default
      Removed value: -256
    • addedInput schema / properties / bed_x_mm / description
      Added value: +"Default: 256.0."
    • removedInput schema / properties / bed_y_mm / default
      Removed value: -256
    • addedInput schema / properties / bed_y_mm / description
      Added value: +"Default: 256.0."
    • addedInput schema / properties / brief_id
      Added value: +{
      +  "description": "Default: \"\".",
      +  "title": "Brief Id",
      +  "type": "string"
      +}
    • removedInput schema / properties / center_on_bed / default
      Removed value: -true
    • addedInput schema / properties / center_on_bed / description
      Added value: +"Default: true."
    • removedInput schema / properties / output_path / default
      Removed value: -""
    • addedInput schema / properties / output_path / description
      Added value: +"Default: \"\"."
    • removedInput schema / properties / printer_id / default
      Removed value: -""
    • addedInput schema / properties / printer_id / description
      Added value: +"Default: \"\"."
  3. First observedv0.1.0

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations: it discloses the external OpenSCAD dependency, that output is written to a file path (temp by default), the exact return payload (path, SCAD code, triangle count, bed_centered flag and translation), automatic decimation of oversized meshes on the 3D stage, and the rationale behind the printer-damaging default with a concrete incident. The center_on_bed narrative explains the physical consequence of the setting, which no annotation conveys.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Headers and front-loading are good — the purpose and safety default come first, and the operation-format grammar is easy to scan. However the operation dict structure is specified twice (once in the prose format section, once in the ':param operations' block) and the param block duplicates the input schema almost word for word, adding bulk without value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

There is no output schema, and the description compensates by documenting the return dict contents. Combined with the dependency requirement, the safety-default mechanics, the full primitive grammar, and the stage/preview behavior, an agent has everything needed to construct a valid call and anticipate the result.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline would be 3, but the description supplies the primitive shape parameter table (cube size, cylinder h/r/r1/r2, torus major_r/minor_r, etc.) that the operations schema explicitly defers to ('Shape params are listed in the tool description'). That is essential meaning unavailable in structured fields. It loses a point because the per-parameter ':param' block mostly restates the schema descriptions verbatim rather than adding new information.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource (build a part by composing primitives with booleans) and immediately differentiates itself from the sibling approach of text-to-mesh AI generation, framing itself as the deterministic CAD path. An agent can tell what this produces and how it differs from a generative mesh tool without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear selection context (use this instead of text-to-mesh guessing when exact functional geometry is needed) and an explicit when-not for the boolean flag ('set center_on_bed=False only if your downstream flow expects origin-centered geometry'). The MAKE DOORS note routes the agent toward compile_scad for the make/preview/iterate loop. It stops short of naming nearby siblings such as compose_models, boolean_mesh_op, or compile_scad with explicit selection criteria.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Deploy Server

Other Tools