{
  "schemaVersion": 1,
  "scope": "local",
  "tools": [
    {
      "name": "evaluate_script",
      "description": "Use this when you need to run a script and check it compiles. Full local builds return viewerUrl: a live Studio link reused and updated on later full builds in the same MCP process. Hosted builds return viewerMode: hosted and viewerHint pointing to open_in_studio; they do not start a loopback viewer. Full evaluations return step evidence: build validity, volume and before/after local PNG paths in one shared iso frame. Snapshots require PW_CDP_URL for an existing browser; unavailable captures report an explicit error. Run a kernelCAD .kcad.ts script and report pass/fail + feature count + diagnostics + sceneSummary (BREP validity, volume in mm³, face count, bounding size in mm). When the scene is assembly-built (assembly().part(...) → .model()/.solvedModel()), also returns a parts summary { count, names } AND runs the mechanism-truth gate by default: the `mechanism` field reports real/broken/unverified and a broken mechanism (disconnected components / mechanism.orphan-part, self-collision, fastened drift, dof-mismatch) makes ok:false with the failures in diagnostics, as does a mate connector more than 6 mm outside its part bounding box (assembly.mechanical.connector-not-in-solid, the same error review_cad reports) — a mechanism (any mate or joint) needs every part linked by connectors + mates/joints (axis+revolute for shafts/hinges/gears; frame+fastened for rigid; or arm.revolute/.prismatic/.ball/.fixed). A plain multi-part assembly with no mates (base + lid, print layout) is independent bodies and passes. Pass { skipMechanismCheck: true } to opt out (e.g. a deliberately free part next to a mechanism). An animation or drive on a fastened joint (mechanism.motion-on-fixed-joint) is broken: animate a revolute/prismatic mate pose. For a model with moving joints or motion intent, `mechanismSummary.statement` is one plain line: \"Motion checked: ...\" names what ran; \"Motion not checked: ...\" is NOT a pass — never call that mechanism working. Every union() is checked too (no opt-out): union.disconnected (the union is several separate solids — a floating operand) and union.member-overlap (two operands that each carry their own .finish()/.material(), the same one, share > 1 mm³ — cut members to fit, e.g. a cross tube between rails is span minus two rail widths) make ok:false. Pass either { file: \"<path>\" } or { code: \"<inline source>\" }. Set { dryRun: true } for fast validation while iterating: transpile + capture + capture-light checks without building solids, DFM gates, or meshing — milliseconds instead of seconds (100x+ on boolean/fillet-heavy scripts). A dry run catches script throws, capture-time API misuse, and assembly validity-gate failures, but NOT lowering failures or dfmSpec diagnostics; it leaves the active session untouched, so finish with a full (non-dry) evaluate_script before using session-dependent tools. To show a measurement in the 3D viewer (e.g. hole spacing), declare it in the script with shape.dimension({ kind: \"linear\", from, to, label }); a full evaluate lists them as dimensions: [{ text, kind, source }], and a shared /p link with ?dims=1 forces them on. A full evaluation updates the active MCP session and viewer state and keeps temporary step evidence; { dryRun: true } leaves the active session unchanged.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "file": {
            "type": "string",
            "description": "Path to a .kcad.ts script file."
          },
          "code": {
            "type": "string",
            "description": "Inline kernelCAD script source."
          },
          "dryRun": {
            "type": "boolean",
            "description": "Fast validation only: skip solid build, DFM gates, and meshing. Does not set or clear the active session."
          },
          "kernel": {
            "type": "string",
            "enum": [
              "occt",
              "smlib"
            ],
            "description": "Solid-modeling kernel. Default 'occt' (OpenCascade); opt-in 'smlib' uses guarded candidates with explicit OCCT fallback diagnostics."
          },
          "skipMechanismCheck": {
            "type": "boolean",
            "description": "Opt out of the default mechanism-truth gate. By default a full evaluation of an assembly-built scene runs checkMechanismTruth and returns a `mechanism` verdict (real/broken/unverified); a broken mechanism makes ok:false. Set true to skip the sweep entirely (no `mechanism` field, no cost). Ignored for dryRun and non-assembly scripts."
          },
          "baseline": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "The `selections` of an earlier evaluation of this model. A selector that now binds to a different face or edge is reported as selector.binding-changed (warning), one whose entity only moved or resized as selector.binding-moved (info). Defaults to the previous evaluation of the same `file`."
          },
          "requirements": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Call-time external requirements ([{ name, predicate }]) measured in the same `requirements` ledger, tagged source: 'external' and never persisted. The predicate is the serializable form of require(): { metric: clearance | distance | mass | volume | bbox | centerOfMass | count | innerLoops | angle | concentric | coplanar, a?, b?, op: gte | lte | eq | between | within, limit, tolerance?, density? }. Operands are { kind: body | faces | edges | part, ref: <feature id/name or part name>, query? }."
          }
        }
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": true
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "sceneSummary": {
            "type": "object",
            "properties": {
              "valid": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "BREP validity, independent of DFM/mechanism/tool success; null if unchecked."
              },
              "volume": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Volume in mm³; assembly parts summed, including overlaps."
              },
              "faceCount": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "BREP faces, summed per assembly part; not mesh triangles."
              },
              "size": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3,
                "description": "Conservative world AABB size [x,y,z] in mm."
              }
            },
            "required": [
              "valid",
              "volume",
              "faceCount",
              "size"
            ],
            "additionalProperties": false
          },
          "ok": {
            "type": "boolean",
            "description": "Whether the script compiled and lowered cleanly."
          },
          "viewerUrl": {
            "type": "string",
            "description": "Live loopback Studio URL; reused on later full builds in the same local MCP process."
          },
          "viewerError": {
            "type": "string",
            "description": "Viewer provisioning error; separate from the CAD build result."
          },
          "viewerMode": {
            "type": "string",
            "enum": [
              "hosted"
            ],
            "description": "Hosted mode uses open_in_studio instead of a process-local viewer."
          },
          "viewerHint": {
            "type": "string",
            "description": "How to view the built model in hosted Studio."
          },
          "step": {
            "type": "object",
            "additionalProperties": true,
            "description": "Per-step build validity, volume and paired local PNG paths with a shared iso frame; unavailable snapshots report an error. Not a topology certificate. Omitted on dry runs."
          },
          "featureCount": {
            "type": "number",
            "description": "Number of features captured by the script."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "dryRun": {
            "type": "boolean",
            "description": "True when the result came from a fast dry run."
          },
          "parts": {
            "type": "object",
            "additionalProperties": true,
            "description": "Assembly parts summary { count, names } when the scene is assembly-built."
          },
          "featureHealth": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "featureId": {
                  "type": "string"
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "warning",
                    "error"
                  ]
                }
              },
              "required": [
                "featureId",
                "status"
              ],
              "additionalProperties": false
            },
            "description": "Per-feature health degradations — ONLY features that fell back to a passthrough (warning) or failed to lower (error). Empty when every feature is healthy. Surfaces which feature degraded even when ok is true."
          },
          "selections": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "What each feature's selectors bound to: { consumerFeatureId, selectorText, syntax: lineage | topoRef | query, fingerprints[] (entity kind, surface type, producing feature, direction, radius, size, centroid), partDiagonal }. Pass back as `baseline` to learn which selectors an edit re-bound. Omitted when no feature used a selector."
          },
          "requirements": {
            "type": "object",
            "additionalProperties": true,
            "description": "One requirements ledger: { ok, summary: { pass, fail, notEvaluated }, entries: [{ name, source: script | external | dfm | fea | mechanical, status: pass | fail | not-evaluated, measured, limit, margin, selections[] with S1 fingerprints, message? }] }. The ledger is the repair signal: it names the requirement, the measured value, the limit and the exact selections. ok is true only when every entry passed; a not-evaluated entry is never green."
          },
          "dimensions": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "text": {
                  "type": "string"
                },
                "kind": {
                  "type": "string",
                  "enum": [
                    "linear",
                    "diameter",
                    "radius",
                    "angular"
                  ]
                },
                "source": {
                  "type": "string",
                  "enum": [
                    "declared",
                    "auto"
                  ]
                }
              },
              "required": [
                "text",
                "kind",
                "source"
              ],
              "additionalProperties": false
            },
            "description": "Dimensions declared with shape.dimension(), as the viewer labels them (e.g. \"hole spacing 30\"). Omitted when the script declares none."
          },
          "tubes": {
            "type": "object",
            "properties": {
              "lines": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "from": {
                      "type": "object",
                      "properties": {
                        "tube": {
                          "type": "string",
                          "description": "Name of the other tube of the joint."
                        },
                        "at": {
                          "type": "number",
                          "description": "Station of the tee: mm along the trunk centreline from the trunk's from end."
                        }
                      },
                      "required": [
                        "tube",
                        "at"
                      ],
                      "additionalProperties": false,
                      "description": "Set when the from end branches off another tube: the trunk and the station of the tee on it. The cut length and bend table of this tube then start on the trunk wall. Omitted for any other end."
                    },
                    "to": {
                      "type": "object",
                      "properties": {
                        "tube": {
                          "type": "string",
                          "description": "Name of the other tube of the joint."
                        },
                        "at": {
                          "type": "number",
                          "description": "Station of the tee: mm along the trunk centreline from the trunk's from end."
                        }
                      },
                      "required": [
                        "tube",
                        "at"
                      ],
                      "additionalProperties": false,
                      "description": "Set when the to end branches off another tube: the trunk and the station of the tee on it. Omitted for any other end."
                    },
                    "branches": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "tube": {
                            "type": "string",
                            "description": "Name of the other tube of the joint."
                          },
                          "at": {
                            "type": "number",
                            "description": "Station of the tee: mm along the trunk centreline from the trunk's from end."
                          }
                        },
                        "required": [
                          "tube",
                          "at"
                        ],
                        "additionalProperties": false,
                        "description": "One tube that branches off this one."
                      },
                      "description": "The tubes that branch off this one, by station. Omitted when there are none."
                    }
                  },
                  "additionalProperties": true
                },
                "description": "One entry per tube: name, system, od, wall, bendRadius, material, cutLength (mm), bends, xyz (bend-table corner points), lra (length/rotation/angle rows), lastStraight, minStraight, minClearance { mm, to, at } (exact nearest part or tube), massKg (null without a known material or density), volumeInternalMl, pressureDropKPa (null without a declared flow)."
              },
              "systems": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": true
                },
                "description": "One entry per named system: { system, lines, cutLength, massKg }."
              }
            },
            "required": [
              "lines",
              "systems"
            ],
            "additionalProperties": false,
            "description": "Tube line report. Present only when the model has tubes; the gate diagnostics are in diagnostics."
          },
          "ports": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "part": {
                  "type": "string",
                  "description": "The assembly part that owns the port."
                },
                "name": {
                  "type": "string",
                  "description": "The connector name; part.port(name) gives this port to tube()."
                },
                "system": {
                  "type": "string"
                },
                "od": {
                  "type": "number",
                  "description": "Tube outer diameter the port takes, mm."
                },
                "minStraight": {
                  "type": "number",
                  "description": "Straight a tube must keep leaving the port, mm. Omitted when the port declares none."
                },
                "origin": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  },
                  "description": "Port position [x, y, z] in assembly space, mm, with params and mates resolved. Omitted when unresolved is set."
                },
                "axis": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  },
                  "description": "Unit axis [x, y, z] pointing out of the part, assembly space. Omitted when unresolved is set."
                },
                "placedBy": {
                  "type": "string",
                  "enum": [
                    "at",
                    "connect",
                    "mate"
                  ],
                  "description": "'at': the part is where its at puts it. 'connect': the part is where its connect puts it. For both, part.port(name) gives this position. 'mate': a mate or joint moved or turned the part after that; origin and axis are the solved ones, and part.port(name) still gives the position before the solve. Omitted when unresolved is set."
                },
                "usedBy": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Names of the tubes that end on the port; empty when the port is free."
                },
                "unresolved": {
                  "type": "string",
                  "description": "Why the position is missing: the script does not build the assembly, the part failed to build, another part failed so the solve did not run and this part is positioned by a mate, a joint or connect, the part is not in the built assembly, or the connector origin is a topology reference or not numeric. Omitted when origin is given."
                }
              },
              "required": [
                "part",
                "name",
                "system",
                "od",
                "usedBy"
              ],
              "additionalProperties": false
            },
            "description": "Every fluid port (a connector with port data) of the assembly the script returns. Present, possibly empty, whenever the script declares an assembly and builds a model, with or without tubes; omitted otherwise and for dryRun."
          },
          "mechanism": {
            "type": "string",
            "enum": [
              "real",
              "broken",
              "unverified"
            ],
            "description": "Mechanism-truth verdict for an assembly-built scene (default-on; omitted for dryRun, non-assembly, or skipMechanismCheck:true). 'broken' makes ok:false; 'unverified' keeps ok and surfaces a loud budget diagnostic."
          },
          "mechanismSummary": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "verdict",
              "maxLevel",
              "statement",
              "checked",
              "skipped",
              "failures"
            ],
            "description": "Plain verdict for a model with moving joints or motion intent (animation, drive, transmission); absent for a static model. Read `statement`: 'Motion checked' names what ran, 'Motion not checked' names what was skipped (NOT a pass), 'Mechanism broken' names the joint.",
            "properties": {
              "verdict": {
                "type": "string",
                "enum": [
                  "real",
                  "broken",
                  "unverified"
                ]
              },
              "maxLevel": {
                "type": "string",
                "enum": [
                  "ok",
                  "warning",
                  "error"
                ],
                "description": "One status level: 'error' when broken, 'warning' when not checked, 'ok' when checked."
              },
              "statement": {
                "type": "string",
                "description": "One line. Quote it instead of calling the mechanism working."
              },
              "checked": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "What ran and held (verdict 'real')."
              },
              "skipped": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "What did not run and why. On 'real', the moving joint DOFs with no limits (range not checked)."
              },
              "failures": {
                "type": "array",
                "description": "Error failures (verdict 'broken'); `joint` names the mate and `part` the part when known.",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "code",
                    "reason"
                  ],
                  "properties": {
                    "code": {
                      "type": "string"
                    },
                    "reason": {
                      "type": "string"
                    },
                    "joint": {
                      "type": "string"
                    },
                    "part": {
                      "type": "string"
                    }
                  }
                }
              },
              "loads": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "maxLevel",
                  "statement"
                ],
                "description": "Motion-load line, present when a mechanicalJoint declares torqueNm. Full table: verify({ check: 'motion-load' }).",
                "properties": {
                  "maxLevel": {
                    "type": "string",
                    "enum": [
                      "ok",
                      "warning",
                      "error"
                    ]
                  },
                  "statement": {
                    "type": "string"
                  },
                  "joints": {
                    "type": "array",
                    "description": "Compact per-joint loads for the Studio Loads panel: peaks, support radial loads, and [tMs, torqueNm] pairs.",
                    "items": {
                      "type": "object",
                      "additionalProperties": true,
                      "required": [
                        "joint",
                        "peakTorqueNm"
                      ]
                    }
                  }
                }
              }
            }
          },
          "reviewHint": {
            "type": "string",
            "description": "Present only when a captured assembly declares articulated (non-fastened) mates: the default mechanism check is shallow (no joint-support intents, pose-envelope overlap at declared limits, or gravity drop) — run review_cad for pose-envelope + gravity checks."
          }
        },
        "required": [
          "ok",
          "featureCount",
          "diagnostics",
          "sceneSummary"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "diff_scripts",
      "description": "Use this when you need to see exactly what changed between two script versions. Structured geometric delta between two versions of a kernelCAD script — a baseline ({ baseFile } or { baseCode }) and a revision ({ file } or { code }). Returns agent-readable JSON: per-part added/removed/renamed/changed (volume mm³ + exact bbox deltas, numbers matching inspect({ of: 'part-stats' })), total interference-volume delta with per-pair detail, mate-graph changes (added/removed/changed mates incl. type, connectors, pose, limits), and param changes (value/min/max). Single-shape scripts diff as one \"(root)\" pseudo-part; a `return [a, b]` multi-body script diffs per body as \"body[0]\", \"body[1]\". An error that still leaves geometry (e.g. a skipped fillet) is listed under base/revised.errors beside the diff. Use after editing a script to verify exactly what changed physically before re-rendering. On a hosted server pass both versions inline: { baseCode: 'return box(10, 10, 10);', code: 'return box(10, 10, 12);' } (base_code/old_code/before and revised_code/new_code/after are accepted as aliases). Read-only — never touches the active session.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "baseFile": {
            "type": "string",
            "description": "Baseline (before) script — path to a .kcad.ts file. Local servers only."
          },
          "baseCode": {
            "type": "string",
            "description": "Baseline (before) script — inline source. One of baseFile / baseCode is required."
          },
          "file": {
            "type": "string",
            "description": "Revised (after) script — path to a .kcad.ts file. Local servers only."
          },
          "code": {
            "type": "string",
            "description": "Revised (after) script — inline source. One of file / code is required."
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "base": {
            "type": "object",
            "additionalProperties": true,
            "description": "Baseline summary { featureCount, partCount, isAssembly, errors? } (success); errors lists error diagnostics that still left geometry to diff."
          },
          "revised": {
            "type": "object",
            "additionalProperties": true,
            "description": "Revision summary { featureCount, partCount, isAssembly, errors? } (success)."
          },
          "parts": {
            "type": "object",
            "additionalProperties": true,
            "description": "Per-part added/removed/renamed/changed/unchanged (success)."
          },
          "interference": {
            "type": "object",
            "additionalProperties": true,
            "description": "Total interference-volume delta + per-pair detail (success)."
          },
          "mates": {
            "type": "object",
            "additionalProperties": true,
            "description": "Mate-graph changes (success)."
          },
          "params": {
            "type": "object",
            "additionalProperties": true,
            "description": "Param value/min/max changes (success)."
          },
          "deeperDiffAvailable": {
            "type": "object",
            "additionalProperties": true,
            "description": "Present when the diff touched geometry-affecting ops: { tool: 'diff_geometry', reason, bodies } — the same two scripts can be compared at material level (added/removed/common volume + per-body verdict)."
          },
          "side": {
            "type": "string",
            "description": "Which side failed ('base' | 'revised') (failure)."
          },
          "error": {
            "type": "string",
            "description": "Failure message (failure)."
          },
          "errorCode": {
            "type": "string"
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "inspect",
      "description": "Use this when you need to read facts about a model. One reader, selected by `of`:\n- 'assembly' — physical assembly inventory (parts, bboxes, connectors, mates, disconnected solids).\n- 'robot' — URDF/SDFormat export preview (links, joints, planning groups, end-effectors, issues).\n- 'step' — inspect an imported STEP file: solid tree, exact bbox/volume, cylindrical holes (breached bores flagged partial; holeDetection: 'exact' | 'heuristic').\n- 'shape' — volume / surfaceArea / bbox for one feature ({ feature_id? }).\n- 'mass' — mass, centre of mass, centroidal inertia tensor (inertia6 + 3x3 inertiaMatrix), principalMoments/principalAxes, symmetry flags, and optionally the radius of gyration about an arbitrary axis ({ feature_id?, density?, gyration_axis? }); density in kg/m^3, defaults to 1000 (water).\n- 'features' — features captured by the script (kind, id, params, transforms, suppression).\n- 'assemblies' — assembly intent (assemblies, parts, connectors, joints).\n- 'topology' — canonical face names + edge count for a feature ({ feature_id? }).\n- 'edges' — edges of a shape with optional EdgeQuery ({ feature_id?, query? }); returns @kc[...] refs.\n- 'face-edges' — boundary edges of a named canonical face ({ feature_id?, face_name }).\n- 'faces' — faces of a shape with optional FaceQuery ({ feature_id?, query? }); returns @kc[...] refs.\n- 'face-labels' — user-applied labels visible in the script.\n- 'mates' — mates captured by the script.\n- 'constraints' — sketch constraints captured by the script.\n- 'part-stats' — bundled parts-catalog statistics.\n- 'bend-table' — sheet-metal bend table for a flattened pattern.\n- 'params' — declared model parameters.\n- 'part-categories' — top-level part-catalog categories available in the bundled (and configured remote) catalog.\n- 'part-families' — part families within a category ({ category? }); count + exemplar ids per family.\n- 'bom' — bill of materials ({ assembly? }): one row per distinct part (grouped by geometry/catalog identity, not name) with real instance quantity, kind ('fabricated'|'purchased'), material, density, per-unit and total mass, bbox, a fabrication process (`process` + `processSource`), catalog provenance for purchased parts, and totals; `bom.*` diagnostics flag rows with no density source or missing catalog vendor info instead of guessing.\n- 'section' — numeric cross-section probe of a shape: area, perimeter, loop/hole counts, 2D bbox at a plane ({ feature_id?, plane | at+axis, stack?: { from, to, count, axis? } }). `stack` scans evenly spaced slices and returns `minAreaIndex`/`minAreaPosition` — use it to find the neck/thinnest cross-section along an axis.\n- 'continuity' — G0/G1/G2 classification of shared edges ({ feature_id?, edges? }); position gap, normal jump, curvature difference, worst-sample XYZ.\n- 'curvature' — per-face Gaussian and mean curvature min/max/mean, inflections, spikes ({ feature_id?, faces?, spike_factor? }).\n- 'multi-material' — explicit material leaves shadowed by later attributed boolean descendants, with assembly-part rewrite templates; analyzes capture records and does not change mesh attribution.\nAll params except `of` are subject-specific and forwarded verbatim. Most subjects accept { file | code }.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "of": {
            "type": "string",
            "enum": [
              "assembly",
              "robot",
              "step",
              "shape",
              "mass",
              "features",
              "assemblies",
              "topology",
              "edges",
              "face-edges",
              "faces",
              "face-labels",
              "mates",
              "constraints",
              "part-stats",
              "bend-table",
              "params",
              "part-categories",
              "part-families",
              "bom",
              "section",
              "continuity",
              "curvature",
              "multi-material"
            ],
            "description": "Which facts to read."
          },
          "file": {
            "type": "string",
            "description": "Path to a .kcad.ts script file."
          },
          "code": {
            "type": "string",
            "description": "Inline kernelCAD script source."
          },
          "assembly": {
            "type": "string",
            "description": "of:'assembly'|'robot'|'bom' — assembly name; defaults to the first captured assembly."
          },
          "feature_id": {
            "type": "string",
            "description": "of:'shape'|'mass'|'topology'|'edges'|'faces'|'face-edges'|'face-labels' — FeatureId; defaults to the last returned shape."
          },
          "density": {
            "type": "number",
            "description": "of:'mass' — material density in kg/m^3 (steel 7850, aluminium 2700, ABS 1050). Defaults to 1000 (water); the response echoes the value used and flags when it was defaulted."
          },
          "gyration_axis": {
            "type": "object",
            "description": "of:'mass' — optional axis in shape-local mm to report the radius of gyration about. Omit for centroidal quantities only; the result is density-independent and returned in mm.",
            "properties": {
              "origin": {
                "type": "array",
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3,
                "description": "A point on the axis, shape-local mm."
              },
              "direction": {
                "type": "array",
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3,
                "description": "Axis direction; normalised internally, so it need not be a unit vector."
              }
            },
            "required": [
              "origin",
              "direction"
            ]
          },
          "face_name": {
            "type": "string",
            "enum": [
              "top",
              "bottom",
              "left",
              "right",
              "front",
              "back"
            ],
            "description": "of:'face-edges' — canonical face name (required for that subject)."
          },
          "query": {
            "type": "object",
            "description": "of:'edges'|'faces' — optional EdgeQuery/FaceQuery filter."
          },
          "category": {
            "type": "string",
            "description": "of:'part-families' — optional top-level category to filter families by."
          },
          "plane": {
            "type": [
              "string",
              "object"
            ],
            "description": "of:'section' — section plane. Either a cardinal name string 'xy'|'xz'|'yz', { plane: 'xy'|'xz'|'yz', offset? }, or { origin: [x,y,z], normal: [nx,ny,nz] }. Omit to use `at`+`axis`."
          },
          "at": {
            "type": "number",
            "description": "of:'section' — single slice position along `axis` (mm)."
          },
          "axis": {
            "type": "string",
            "enum": [
              "x",
              "y",
              "z"
            ],
            "description": "of:'section' — normal axis for `at` / `stack` (default 'z')."
          },
          "stack": {
            "type": "object",
            "description": "of:'section' — dense scan: `count` slices evenly spaced from `from` to `to` along `axis`; response reports minAreaIndex/minAreaPosition.",
            "properties": {
              "from": {
                "type": "number",
                "description": "Start position along the axis (mm)."
              },
              "to": {
                "type": "number",
                "description": "End position along the axis (mm)."
              },
              "count": {
                "type": "integer",
                "description": "Number of evenly spaced slices (>= 1)."
              },
              "axis": {
                "type": "string",
                "enum": [
                  "x",
                  "y",
                  "z"
                ],
                "description": "Scan axis (default 'z')."
              }
            },
            "required": [
              "from",
              "to",
              "count"
            ]
          },
          "edges": {
            "type": [
              "object",
              "array",
              "string"
            ],
            "description": "of:'continuity' — optional EdgeQuery or @kc[...] ref(s) limiting which shared edges are sampled."
          },
          "faces": {
            "type": [
              "object",
              "array",
              "string"
            ],
            "description": "of:'curvature' — optional FaceQuery or @kc[...] ref(s) limiting which faces are sampled."
          },
          "spike_factor": {
            "type": "number",
            "description": "of:'curvature' — spike sensitivity as a multiple of the face's Gaussian stddev (default 6)."
          }
        },
        "required": [
          "of"
        ]
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": true
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "description": "Whether the read succeeded."
          },
          "error": {
            "type": "string",
            "description": "Failure message (present on failure)."
          },
          "errorCode": {
            "type": "string"
          }
        },
        "required": [],
        "additionalProperties": true
      }
    },
    {
      "name": "verify",
      "description": "Use this when you need to check a design against a rule set. One verifier, selected by `check`:\n- 'assembly' — static assembly review ({ file | code }, or the session evaluate_script left): mate validator, default-pose interference, joint topology, mechanical plausibility. ok:false with `blocking[]` exactly when review_cad's blocking rules fire on these findings; review_cad also sweeps joint ranges and runs physics.\n- 'urdf' — structural validity of a .urdf file ({ urdf_path }).\n- 'dfm' — print-readiness gates declared by dfmSpec() ({ file | code }).\n- 'dfm-preflight' — sheet-metal flat pattern vs a job-shop's ordering rules ({ vendor, material, thicknessIn|thicknessMm, ... }). Returns the vendor's catalog source pages as `sources`; when `disclosure` is present, show it with those links.\n- 'assembly-path' — continuous straight-line removal of each assembly part along ±X/±Y/±Z and optional world-space directions. Returns valid directions, blocking parts and one of three states (removable / blocked / unknown); sequence peels the directional blocking graph and reverses it into a build sequence with a model stamp. Fastened-mate and fixed-connect clusters become subassemblies: each is planned recursively inside and installed as one unit at the top level (`Step.subassembly`). Remaining valid orders use deterministic heuristics (subassemblies first, outside-in, fewest reorientations, fewest tool changes); stuck sets get a budgeted blocking-reduction partition and a sampling fallback whose paths are labelled found-by-search, never proven. A fastener with a fastened-mate `fastener` declaration (axis, pitch, optional tool envelope) is tested along its helical path and reported `motion: helical`; a press/snap `fit` declaration becomes a `requires-force` step, never simulated. A modelled driver/socket/hex-key envelope swept along the approach axis adds `toolBlocked` { fastener, blockers } and a failing S2 ledger entry; unmodelled tools add nothing. Threaded fasteners without metadata stay unknown: non-straight-path. `stability: true` adds an approximate P3 support check at each build step: each part's mesh centre of mass must project inside the support polygon of its contacts with already-stable parts (declared or inferred base/fixture under `gravity`, default [0,0,-1]); unsupported parts become `needsHold` { part, reason, supports } and their steps carry `stability: 'needs-hold'`, while stable steps may carry `heldBy`. This is a projection, not gravity simulation, friction, tipping or fixture analysis. disassemblyOrder runs a deterministic greedy removal pass. Watertight mesh approximation, conservative contact, no rotation/mate/hardware certification.\n- 'swept-collision' — sweep declared joint range(s) and report colliding poses.\n- 'reachable' — inverse-kinematics reachability for an end-effector ({ tip_link, target_position, ... }).\n- 'geometry-quality' — one solid body's BREP tiny faces and short edges (ids, locations, mm²/mm), plus sampled mirror symmetry about centroid XY/YZ/XZ and principal inertia planes ({ file | code, feature_id?, tiny_face_area_mm2?, tiny_face_relative?, short_edge_length_mm?, symmetry_tolerance_mm?, mesh_deflection_mm?, asserted_plane?: { origin, normal } }). Relative area is a fraction of total surface area; thresholds are ORed. Candidate planes are discovery; only an asserted plane gates symmetry. Approximate sampled tessellation, not exact BREP proof.\n- 'fastener-installation' — measured explicit catalog-screw installation stations on lowered assembly BREP ({ file | code, fasteners:[{ part, against, engagementPart?, minEngagementMm?, maxProtrusionMm? }], toleranceMm?, angleToleranceDeg? }). Reports annular bearing gap, bore axis/diameter/overlap and receiver geometric engagement/protrusion. Unknown or zero coverage cannot pass. Simplified threads do not certify torque, preload or strength.\n- 'mounting-holes' — fastened mates: hole pairs one screw can use (equal, or clearance over a tap drill / hole({ thread }) of the same metric size; hole-free faces are a rigid bond) and fastener holes meeting at the contact face are coaxial. Sides it cannot resolve are info, never mismatches.\n- 'load-capacity' — will it hold? Closed-form Euler-Bernoulli beam check ({ loads, materials, ... }), or mode:'fea' to solve the script's feaStudy (quadratic-tet FEA, CalculiX) — both return { ok, safetyFactor, elements[{ partName, stressPa, yieldPa, safetyFactor }], failures[], diagnostics }; fea adds the threshold, the stress regions as @kc[...] faces with their location, and fea { peakStressPa, maxDisplacementMm, meshTrusted, peakAtSupportPa, refinement }; it refines the mesh automatically until the stress is trusted (refine: false for one solve).\n- 'static-hold' — gravitational holding torque/force at a sampled pose grid vs each actuated joint's declared actuator capacity ({ joint?, pose?, gravity?, min_torque_margin_pct?, range_samples? }).\n- 'motion-load' — loads on each driven joint (mechanicalJoint on a revolute mate) while the model moves: gravity, inertia from the animationView tracks (finite differences), optional external forces. Mass and inertia come from the solids and density/material, or a part's massKg. Returns per joint peak torque vs the mechanicalJoint torqueNm (margin; < 1x error, < 2x warning), axial / radial force and bending moment on the actuator shaft (checked only against radialLimitN / axialLimitN; without them 'no rating, not checked'), the radial load on each of up to two coaxial supports (each at its station on the shaft: the actuator at the joint origin, else the support's connector on the axis, else the middle of its material nearest the shaft; an ambiguous station is a mechanism.load.not-resolved warning, not a number), the worst pose, a torque-vs-time series, and `partLoads` (the worst wrench per part and side in that part's own frame, which `feaStudy({ loadsFrom })` consumes) ({ file | code, motion_mode?: 'tracks'|'range'|'poses', motion_poses?: [{ joint: value }], sample_ms?, range_samples?, quasi_static?, gravity?, motion_loads?: [{ part, point, force, fromMs?, toMs? }], supports?: { joint: [parts] }, series_points? }). Pass supports to compare with and without a bushing. Rigid bodies, tree mate graphs, no friction.\n- 'physics' — full mechanism truth with physics engine: kinematic disconnect / interference / DOF checks plus static equilibrium and drop-on-release under gravity ({ file | code, assembly?, physics? }). Returns { ok, mechanism: 'real'|'broken'|'unverified', failures[], coverage }.\n- 'edge-radius' — general edge-break specification on final BREP ({ file | code, min_radius_mm?, max_radius_mm?, require_edge_break?: 'external'|'internal'|'all', feature_id?, assembly?, parts?, edges?, faces? }). Reports sharp convex/concave edges, analytic cylindrical/toroidal fillet radii and spherical junctions, and heuristic planar chamfer strips. Radius bounds apply only to fillets; selectors/points are part-local. Unknown/empty coverage cannot pass.\nAll params except `check` are check-specific and forwarded verbatim; each check fails closed on its own missing required params.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "check": {
            "type": "string",
            "description": "Which verification to run. Omit only when passing call-time `requirements`; then the requirements ledger is the verification.",
            "enum": [
              "assembly",
              "urdf",
              "dfm",
              "dfm-preflight",
              "swept-collision",
              "reachable",
              "mounting-holes",
              "load-capacity",
              "static-hold",
              "motion-load",
              "fastener-installation",
              "geometry-quality",
              "assembly-path",
              "edge-radius",
              "physics",
              "requirements"
            ]
          },
          "requirements": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Call-time external requirements ([{ name, predicate }]) measured in the same ledger as script require(), dfmSpec and feaStudy, tagged source: 'external' and never persisted. The predicate is the serializable form of require(): { metric: clearance | distance | mass | volume | bbox | centerOfMass | count | innerLoops | angle | concentric | coplanar, a?, b?, op: gte | lte | eq | between | within, limit, tolerance?, density? }. Operands are { kind: body | faces | edges | part, ref: <feature id/name or part name>, query? }. With `check` omitted the ledger is the whole verification; check 'requirements' is the explicit form."
          },
          "file": {
            "type": "string",
            "description": "Path to a .kcad.ts script (assembly/dfm/dfm-preflight/swept-collision/reachable/mounting-holes/load-capacity/static-hold/geometry-quality/edge-radius/requirements)."
          },
          "code": {
            "type": "string",
            "description": "Inline kernelCAD script source (same checks as `file`)."
          },
          "feature_id": {
            "type": "string",
            "description": "check:'geometry-quality' — body feature to measure; defaults to script return. check:'edge-radius' — lowered feature; default the returned model."
          },
          "tiny_face_area_mm2": {
            "type": "number",
            "minimum": 0,
            "default": 0.01,
            "description": "check:'geometry-quality' — flag faces strictly below this absolute area; zero disables."
          },
          "tiny_face_relative": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "default": 0,
            "description": "check:'geometry-quality' — fraction of total BREP surface area, ORed with absolute threshold."
          },
          "short_edge_length_mm": {
            "type": "number",
            "minimum": 0,
            "default": 0.1,
            "description": "check:'geometry-quality' — flag edges strictly below this length; zero disables."
          },
          "symmetry_tolerance_mm": {
            "type": "number",
            "minimum": 0.000001,
            "default": 0.05,
            "description": "check:'geometry-quality' — maximum sampled mirror-to-mesh distance, mm."
          },
          "mesh_deflection_mm": {
            "type": "number",
            "minimum": 1e-7,
            "description": "check:'geometry-quality' — absolute mesh deflection, defaults to tolerance/4; must be <= tolerance/2."
          },
          "asserted_plane": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "origin",
              "normal"
            ],
            "description": "check:'geometry-quality' — optional required mirror plane in model coordinates; normal is normalized and must be nonzero.",
            "properties": {
              "origin": {
                "type": "array",
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3
              },
              "normal": {
                "type": "array",
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3
              }
            }
          },
          "assembly": {
            "type": "string",
            "description": "Assembly name; defaults to the first captured assembly."
          },
          "min_radius_mm": {
            "type": "number",
            "minimum": 0,
            "description": "check:'edge-radius' — minimum fillet radius in mm (does not imply sharp-edge prohibition)."
          },
          "max_radius_mm": {
            "type": "number",
            "minimum": 0,
            "description": "check:'edge-radius' — maximum fillet radius in mm; must be >= min_radius_mm."
          },
          "require_edge_break": {
            "type": "string",
            "enum": [
              "external",
              "internal",
              "all"
            ],
            "description": "check:'edge-radius' — prohibit sharp convex/external, concave/internal, or all edges."
          },
          "parts": {
            "type": "array",
            "minItems": 1,
            "uniqueItems": true,
            "items": {
              "type": "string",
              "minLength": 1
            },
            "description": "check:'edge-radius' — explicit assembly part names (default all)."
          },
          "edges": {
            "type": [
              "object",
              "array",
              "string"
            ],
            "description": "check:'edge-radius' — EdgeQuery or @kc[...] edge ref(s); intersected with faces. Query near sorts, it does not filter."
          },
          "faces": {
            "type": [
              "object",
              "array",
              "string"
            ],
            "description": "check:'edge-radius' — FaceQuery or @kc[...] face ref(s); includes incident edges and fillets on selected faces."
          },
          "fasteners": {
            "type": "array",
            "description": "check:'fastener-installation' — explicit named stations; empty means no coverage.",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "part": {
                  "type": "string",
                  "minLength": 1
                },
                "against": {
                  "type": "array",
                  "minItems": 1,
                  "uniqueItems": true,
                  "items": {
                    "type": "string",
                    "minLength": 1
                  }
                },
                "engagementPart": {
                  "type": "string",
                  "minLength": 1
                },
                "minEngagementMm": {
                  "type": "number",
                  "minimum": 0,
                  "description": "Declared geometric axial overlap minimum; no thread-strength claim."
                },
                "maxProtrusionMm": {
                  "type": "number",
                  "minimum": 0
                }
              },
              "required": [
                "part",
                "against"
              ]
            }
          },
          "toleranceMm": {
            "type": "number",
            "minimum": 0,
            "description": "check:'fastener-installation' — linear tolerance, default .05 mm."
          },
          "angleToleranceDeg": {
            "type": "number",
            "minimum": 0,
            "maximum": 90,
            "description": "check:'fastener-installation' — axis tilt tolerance, default 1 degree."
          },
          "urdf_path": {
            "type": "string",
            "description": "check:'urdf' — path to the .urdf file."
          },
          "dxf": {
            "type": "string",
            "description": "check:'dfm-preflight' — path to a DXF file."
          },
          "featureId": {
            "type": "string",
            "description": "check:'dfm-preflight' — FeatureId to scope to."
          },
          "vendor": {
            "type": "string",
            "description": "check:'dfm-preflight' — vendor SKU (required for that check)."
          },
          "material": {
            "type": "string",
            "description": "check:'dfm-preflight' — material SKU (required for that check)."
          },
          "thicknessIn": {
            "type": "number",
            "description": "check:'dfm-preflight' — material thickness in inches."
          },
          "thicknessMm": {
            "type": "number",
            "description": "check:'dfm-preflight' — material thickness in millimeters."
          },
          "service": {
            "type": "string",
            "enum": [
              "laser",
              "cnc-router",
              "waterjet",
              "bending"
            ],
            "description": "check:'dfm-preflight' — service."
          },
          "refreshCatalog": {
            "type": "boolean",
            "description": "check:'dfm-preflight' — force vendor catalog refresh."
          },
          "directions": {
            "type": "array",
            "maxItems": 64,
            "items": {
              "type": "array",
              "items": {
                "type": "number"
              },
              "minItems": 3,
              "maxItems": 3
            },
            "description": "check:'assembly-path' — additional nonzero world-space removal vectors; normalized and deduplicated."
          },
          "disassemblyOrder": {
            "type": "boolean",
            "description": "check:'assembly-path' — iteratively remove freed parts and return removalOrder or stuckParts."
          },
          "sequence": {
            "type": "boolean",
            "description": "check:'assembly-path' — plan a build sequence { steps, model, unknown, search?, requiresForce?, toolBlocked?, needsHold? }. Fastened/fixed clusters become subassemblies planned inside and installed as one unit; steps carry the insertion direction (reverse removal), and may be motion: helical (declared fastener), requires-force (press/snap, not proven) or search. Stuck sets use a budgeted partition; non-straight paths found by sampling are labelled found-by-search and are not proven. Blocked and unknown parts are not reported as impossible."
          },
          "threadedFasteners": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "check:'assembly-path' — part names that need a helical removal. Catalog screw/bolt/nut families are detected automatically; without a fastened-mate fastener declaration (axis/pitch) they remain unknown: non-straight-path. Declare the motion on arm.mate(..., 'fastened', { fastener: { part, axis, pitchMm, tool? }, fit?: { kind, part? } })."
          },
          "stability": {
            "type": "boolean",
            "description": "check:'assembly-path' — run the approximate P3 static-stability pass on the sequence. Each part's closed-mesh volume centroid (uniform density) must project inside the convex hull of its contacts with already-stable parts. Unsupported parts become needsHold { part, reason, supports } and ok:false; a stable step may carry heldBy. Not a physics simulation."
          },
          "fixtures": {
            "type": "array",
            "uniqueItems": true,
            "items": {
              "type": "string",
              "minLength": 1
            },
            "description": "check:'assembly-path' with stability:true — declared base/fixture part names, stable from step 1. Default: the lowest part(s) along gravity."
          },
          "contactToleranceMm": {
            "type": "number",
            "minimum": 0,
            "description": "check:'assembly-path' with stability:true — surface distance at or below which parts count as touching (default 0.05 mm)."
          },
          "joint": {
            "type": "string",
            "description": "check:'swept-collision' — joint to sweep; omit to sweep every declared joint. check:'static-hold' — joint to evaluate; omit to evaluate every joint with a declared actuator."
          },
          "range": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "minItems": 3,
            "maxItems": 3,
            "description": "check:'swept-collision' — [lower, upper, step] in joint-native units."
          },
          "collision_tolerance_mm3": {
            "type": "number",
            "description": "check:'swept-collision' — BREP intersection volume tolerance (mm^3)."
          },
          "tip_link": {
            "type": "string",
            "description": "check:'reachable' — end-effector part name (required for that check)."
          },
          "target_position": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "minItems": 3,
            "maxItems": 3,
            "description": "check:'reachable' — target [x, y, z] mm (world frame)."
          },
          "target_orientation": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "minItems": 3,
            "maxItems": 3,
            "description": "check:'reachable' — target XYZ Euler angles in radians."
          },
          "position_tolerance_mm": {
            "type": "number",
            "description": "check:'reachable' — position tolerance in mm."
          },
          "orientation_tolerance_rad": {
            "type": "number",
            "description": "check:'reachable' — orientation tolerance in radians."
          },
          "prefer_solver": {
            "type": "string",
            "enum": [
              "analytical",
              "numeric",
              "auto"
            ],
            "description": "check:'reachable' — force the IK path ('auto' default)."
          },
          "max_iterations": {
            "type": "number",
            "description": "check:'reachable' — numeric-path iteration cap."
          },
          "seed": {
            "type": "object",
            "description": "check:'reachable' — numeric IK seed pose (joint name -> deg/mm)."
          },
          "loads": {
            "type": "object",
            "description": "check:'load-capacity' — partName -> { force?: [Fx,Fy,Fz] N, torque?: [Tx,Ty,Tz] N*m }."
          },
          "materials": {
            "type": "object",
            "description": "check:'load-capacity' — partName -> material declaration."
          },
          "mode": {
            "type": "string",
            "enum": [
              "stub",
              "beam",
              "fea"
            ],
            "description": "check:'load-capacity' — 'beam' (default), 'stub', or 'fea' (solve the script's feaStudy: CalculiX + gmsh when installed, else the in-process voxel estimate)."
          },
          "safety_factor_threshold": {
            "type": "number",
            "description": "check:'load-capacity' — pass/fail safety-factor floor (default 1.5; mode 'fea': the study's minSafetyFactor when declared)."
          },
          "study": {
            "type": "string",
            "description": "check:'load-capacity' mode:'fea' — feaStudy name (default: the last declared one)."
          },
          "mesh_size": {
            "type": "number",
            "description": "check:'load-capacity' mode:'fea' — element size override, mm."
          },
          "heatmaps": {
            "type": "boolean",
            "description": "check:'load-capacity' mode:'fea' — also render stress heatmap PNGs (default false)."
          },
          "refine": {
            "type": "boolean",
            "description": "check:'load-capacity' mode:'fea' — one automatic finer pass (0.75x element size) when the stress is untrusted, inside the element budget (default true); false solves once at the study's meshSize."
          },
          "pose": {
            "type": [
              "object",
              "array"
            ],
            "description": "check:'static-hold' — explicit pose (joint name -> deg/mm) or array of poses; omit to sample a grid across the evaluated joint's range."
          },
          "gravity": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "minItems": 3,
            "maxItems": 3,
            "description": "check:'static-hold' — gravity vector, m/s^2, world frame (default [0, 0, -9.81]). check:'assembly-path' with stability:true — gravity direction, world frame, magnitude ignored (default [0, 0, -1])."
          },
          "min_torque_margin_pct": {
            "type": "number",
            "description": "check:'static-hold' — safety-margin floor as a percent of actuator capacity (default 20)."
          },
          "range_samples": {
            "type": "number",
            "description": "check:'static-hold' — grid density per evaluated joint when `pose` is omitted (default 9). check:'motion-load' motion_mode:'range' — grid points per joint (default 5)."
          },
          "motion_mode": {
            "type": "string",
            "enum": [
              "tracks",
              "range",
              "poses"
            ],
            "description": "check:'motion-load' — 'tracks' (default): along the animationView timeline with inertia; 'range': quasi-static grid over each driven joint's limits; 'poses': exactly motion_poses (a user-named pose is one entry)."
          },
          "motion_poses": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": {
                "type": "number"
              }
            },
            "description": "check:'motion-load' motion_mode:'poses' — explicit mate poses, each an object of joint name -> value in degrees."
          },
          "sample_ms": {
            "type": "number",
            "description": "check:'motion-load' — timeline sample step, ms (default 20). Inertia peaks depend on it at keyframe velocity steps."
          },
          "quasi_static": {
            "type": "boolean",
            "description": "check:'motion-load' — drop velocity/acceleration terms (gravity and external loads only)."
          },
          "motion_loads": {
            "type": "array",
            "description": "check:'motion-load' — external forces: [{ part, point: [x,y,z] mm in the part's modeled frame, force: [Fx,Fy,Fz] N world, fromMs?, toMs? }].",
            "items": {
              "type": "object",
              "required": [
                "part",
                "point",
                "force"
              ],
              "properties": {
                "part": {
                  "type": "string"
                },
                "point": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  },
                  "minItems": 3,
                  "maxItems": 3
                },
                "force": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  },
                  "minItems": 3,
                  "maxItems": 3
                },
                "fromMs": {
                  "type": "number"
                },
                "toMs": {
                  "type": "number"
                }
              }
            }
          },
          "supports": {
            "type": "object",
            "description": "check:'motion-load' — mechanicalJoint name -> support part names to use instead of the declared supports (compare with / without a bushing)."
          },
          "series_points": {
            "type": "number",
            "description": "check:'motion-load' — max torque-vs-time points per joint in the result (default 120; 0 omits the series)."
          }
        },
        "required": [
          "check"
        ]
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "checkedEdges": {
            "type": "integer",
            "minimum": 0,
            "description": "edge-radius: selected nondegenerate, nonseam edges."
          },
          "checkedFillets": {
            "type": "integer",
            "minimum": 0,
            "description": "edge-radius: analytic fillet face patches, including spherical junctions."
          },
          "bodies": {
            "type": "array",
            "description": "edge-radius: one local BREP report per solid of each selected part, plus retained unsupported topology.",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "part": {
                  "type": "string"
                },
                "bodyIndex": {
                  "type": "integer",
                  "minimum": 0
                },
                "edges": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "additionalProperties": false,
                    "properties": {
                      "ref": {
                        "type": "string"
                      },
                      "edgeIndex": {
                        "type": "integer",
                        "minimum": 0
                      },
                      "faceIndices": {
                        "type": "array",
                        "items": {
                          "type": "integer",
                          "minimum": 0
                        }
                      },
                      "faceRefs": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      },
                      "kind": {
                        "type": "string",
                        "enum": [
                          "sharp",
                          "smooth",
                          "filleted",
                          "chamfered",
                          "unknown",
                          "seam",
                          "degenerate"
                        ]
                      },
                      "side": {
                        "type": "string",
                        "enum": [
                          "external",
                          "internal",
                          "unknown"
                        ]
                      },
                      "point": {
                        "type": "array",
                        "items": {
                          "type": "number"
                        },
                        "minItems": 3,
                        "maxItems": 3
                      }
                    },
                    "required": [
                      "ref",
                      "edgeIndex",
                      "faceIndices",
                      "faceRefs",
                      "kind",
                      "side",
                      "point"
                    ]
                  }
                },
                "breaks": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "additionalProperties": false,
                    "properties": {
                      "ref": {
                        "type": "string"
                      },
                      "faceIndex": {
                        "type": "integer",
                        "minimum": 0
                      },
                      "edgeIndices": {
                        "type": "array",
                        "items": {
                          "type": "integer",
                          "minimum": 0
                        }
                      },
                      "edgeRefs": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      },
                      "kind": {
                        "type": "string",
                        "enum": [
                          "fillet",
                          "chamfer"
                        ]
                      },
                      "surfaceType": {
                        "type": "string"
                      },
                      "radiusMm": {
                        "type": [
                          "number",
                          "null"
                        ],
                        "description": "Fillet radius in mm; null for planar chamfer strips."
                      }
                    },
                    "required": [
                      "ref",
                      "faceIndex",
                      "edgeIndices",
                      "edgeRefs",
                      "kind",
                      "surfaceType",
                      "radiusMm"
                    ]
                  }
                },
                "violations": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "additionalProperties": false,
                    "properties": {
                      "rule": {
                        "type": "string",
                        "enum": [
                          "min-radius",
                          "max-radius",
                          "required-edge-break"
                        ]
                      },
                      "ref": {
                        "type": "string"
                      },
                      "measuredMm": {
                        "type": "number"
                      },
                      "limitMm": {
                        "type": [
                          "number",
                          "null"
                        ]
                      }
                    },
                    "required": [
                      "rule",
                      "ref",
                      "measuredMm",
                      "limitMm"
                    ]
                  }
                },
                "unknownRefs": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              },
              "required": [
                "part",
                "bodyIndex",
                "edges",
                "breaks",
                "violations",
                "unknownRefs"
              ]
            }
          },
          "ok": {
            "type": "boolean",
            "description": "Whether the verification ran and passed its gate."
          },
          "source": {
            "type": "string",
            "description": "fastener-installation/geometry-quality/assembly-path/edge-radius: local geometry evidence."
          },
          "featureId": {
            "type": "string",
            "description": "geometry-quality: measured body feature."
          },
          "frame": {
            "type": "string",
            "description": "geometry-quality: model coordinate frame for all locations."
          },
          "thresholds": {
            "type": "object",
            "additionalProperties": true,
            "description": "geometry-quality: effective area/length thresholds and total surface area."
          },
          "tinyFaces": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "geometry-quality: rebuild-scoped face id/index, areaMm2, location."
          },
          "shortEdges": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "geometry-quality: rebuild-scoped edge id/index, lengthMm, parametric midpoint location."
          },
          "degenerateEdges": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "geometry-quality: explicit BREP degenerated pole/parameterization edges, ids and locations; excluded from the physical short-edge gate."
          },
          "symmetry": {
            "type": "object",
            "additionalProperties": true,
            "description": "geometry-quality: sampled-mesh-reflection; planes with passed, maxDeviationMm, rmsDeviationMm, sampleCount and worst-point witnesses, matchingPlanes, toleranceMm and meshDeflectionMm."
          },
          "basis": {
            "type": "string",
            "description": "assembly-path: continuous-triangle-mesh."
          },
          "parts": {
            "type": "array",
            "description": "assembly-path: initial per-part removable, validDirections, directions with distanceMm, clear and blockingParts, and the state (removable / blocked / unknown / requires-force). A helical fastener also carries fastener { axis, pitchMm, handedness, threadLengthMm, turns }; a modelled tool carries toolReach.",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "model": {
            "type": "object",
            "additionalProperties": true,
            "description": "assembly-path: model stamp — rigid parts, motionModels (straight-line-translation plus helical-screw / requires-force / sampling-search when used), tested directions, toolReach (not-modelled / swept-envelope), gravity (not-modelled / approximate-support-projection) and stability { gravity, contactToleranceMm, seed, seedSource, massBasis } when P3 ran, mesh tessellation and clearance tolerance."
          },
          "blockingGraph": {
            "type": "object",
            "additionalProperties": true,
            "description": "assembly-path: union of the per-direction blocker sets as part -> blocker -> direction edges."
          },
          "sequence": {
            "type": "object",
            "additionalProperties": true,
            "description": "assembly-path: { steps, model, unknown, search?, requiresForce?, toolBlocked?, needsHold? }. Steps are the reverse of the removal peel with insertion direction; a step may be motion: helical (declared fastener), requires-force (press/snap, never simulated) or search, and with stability:true may be stability: stable / needs-hold plus heldBy. Subassembly steps name the unit and its internal build. search lists sampling paths labelled found-by-search (never proven); unknown lists parts that could not be proven (never \"impossible\")."
          },
          "needsHold": {
            "type": "array",
            "description": "assembly-path: P3 approximate stability findings. Each entry has part, status: needs-hold, reason, supports, centre of mass and the support polygon when one existed. Not a physics proof.",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "removalOrder": {
            "type": "array",
            "description": "assembly-path: deterministic part removal steps, each with part and direction.",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "search": {
            "type": "array",
            "description": "assembly-path: non-straight paths found by the sampling fallback. Each entry has part, status: found-by-search and waypoints; it is evidence inside a finite budget, not a proof.",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "toolReach": {
            "type": "array",
            "description": "assembly-path: swept tool-envelope results. Each entry has fastener, status clear/tool-blocked, blockers, tool and basis. Only modelled tools appear.",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "toolBlocked": {
            "type": "array",
            "description": "assembly-path: fasteners whose modelled tool envelope is obstructed, with the blockers named.",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "requiresForce": {
            "type": "array",
            "description": "assembly-path: declared press/snap fits ordered as requires-force steps. Declared, never simulated or proven.",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "requirements": {
            "type": "object",
            "additionalProperties": true,
            "description": "assembly-path: S2 ledger entries for modelled tool reach (pass/fail) and declared forced fits (not-evaluated). Unmodelled tools add nothing."
          },
          "stuckParts": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "assembly-path: remaining parts when no straight removal is available."
          },
          "assembly": {
            "type": [
              "string",
              "null"
            ],
            "description": "Audited lowered assembly."
          },
          "status": {
            "type": "string",
            "description": "fastener-installation/edge-radius: pass, fail, partial, or no-coverage; partial/zero coverage cannot pass."
          },
          "counts": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "requested": {
                    "type": "integer",
                    "minimum": 0
                  },
                  "measured": {
                    "type": "integer",
                    "minimum": 0
                  },
                  "passed": {
                    "type": "integer",
                    "minimum": 0
                  },
                  "failed": {
                    "type": "integer",
                    "minimum": 0
                  },
                  "unknown": {
                    "type": "integer",
                    "minimum": 0
                  }
                },
                "required": [
                  "requested",
                  "measured",
                  "passed",
                  "failed",
                  "unknown"
                ],
                "additionalProperties": false
              },
              {
                "type": "object",
                "properties": {
                  "faces": {
                    "type": "integer",
                    "minimum": 0
                  },
                  "edges": {
                    "type": "integer",
                    "minimum": 0
                  }
                },
                "required": [
                  "faces",
                  "edges"
                ],
                "additionalProperties": false
              }
            ]
          },
          "stations": {
            "type": "array",
            "description": "Explicit fastener-installation stations only; no whole-assembly certification.",
            "items": {
              "type": "object",
              "properties": {
                "part": {
                  "type": "string"
                },
                "against": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "engagementPart": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "catalogId": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "pass",
                    "fail",
                    "partial"
                  ]
                },
                "metrics": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "part": {
                        "type": [
                          "string",
                          "null"
                        ]
                      },
                      "status": {
                        "type": "string",
                        "enum": [
                          "pass",
                          "fail",
                          "unknown",
                          "not-applicable"
                        ]
                      },
                      "value": {
                        "type": [
                          "number",
                          "null"
                        ]
                      },
                      "unit": {
                        "type": "string",
                        "enum": [
                          "mm",
                          "deg"
                        ]
                      },
                      "limit": {
                        "type": [
                          "number",
                          "null"
                        ]
                      },
                      "basis": {
                        "type": "string"
                      },
                      "repairHint": {
                        "type": [
                          "string",
                          "null"
                        ]
                      }
                    },
                    "required": [
                      "name",
                      "part",
                      "status",
                      "value",
                      "unit",
                      "limit",
                      "basis",
                      "repairHint"
                    ],
                    "additionalProperties": false
                  }
                }
              },
              "required": [
                "part",
                "against",
                "engagementPart",
                "catalogId",
                "status",
                "metrics"
              ],
              "additionalProperties": false
            }
          },
          "limitations": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Coverage and physical limitations of the geometry audit."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Verifier diagnostics (most checks)."
          },
          "error": {
            "type": "string",
            "description": "Failure message (present on failure)."
          },
          "errorCode": {
            "type": "string"
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "why_did_this_fail",
      "description": "Use this when you need to trace why a feature failed. Walk the upstream chain of a failing feature. Returns the diagnostics of the requested feature plus the diagnostics of every upstream feature in topological order (the requested feature is the last entry). Per-code hints are inline on every diagnostic — call lookup_diagnostics for the full catalogue. Pass { file?, code?, feature_id? }.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "file": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "feature_id": {
            "type": "string"
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "feature_id": {
            "type": "string"
          },
          "chain": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Upstream feature diagnostics in topological order; requested feature last."
          },
          "trace": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Every captured feature joined to its call site, AST node range, diagnostics, inputs and dependents."
          },
          "repairRegion": {
            "type": "object",
            "additionalProperties": true,
            "description": "Minimal editable line ranges for the failure: { file, ranges: [{ startLine, endLine, role, featureId?, paramName? }] }."
          },
          "candidates": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Ordered concrete fixes, each with an AST-anchored patch, a predicted effect, and the geometry it was derived from."
          },
          "candidateStatus": {
            "type": "string",
            "enum": [
              "candidates",
              "no-automatic-candidate"
            ],
            "description": "'no-automatic-candidate' means the region is the whole answer — no mechanical fix exists for that diagnostic kind."
          },
          "candidateReason": {
            "type": "string",
            "description": "Why no candidate was derivable."
          },
          "targetDiagnosticId": {
            "type": "string",
            "description": "Id of the diagnostic the repair plan targets; pass it to repair_script."
          },
          "error": {
            "type": "string"
          },
          "errorCode": {
            "type": "string"
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "set_param",
      "description": "Use this when you need to edit a param() default value in a kernelCAD script. Returns the modified code as text plus diagnostics from re-evaluating the result. Caller persists the new code via standard file-write tools (this tool has no side effects). With preview: true it builds the edit in a scratch session instead and returns the diff_geometry summary plus the requirements-ledger and S1 binding diffs (which requirements flip, which margins shrink, which selectors moved or re-bound), without touching the active session, source, revision or caches. A preview whose revised build fails returns ok:false and no diff. Inspect after.requirementsOk to see whether the edit preserves declared intent; preview.ok only says the preview could be computed.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The .kcad.ts source code."
          },
          "param_name": {
            "type": "string",
            "description": "The string literal name of the param (first arg to param())."
          },
          "new_value": {
            "type": [
              "number",
              "boolean",
              "string"
            ],
            "description": "The new default value: number for numeric params, boolean for boolean params, or string for choice/string/color params (must be one of the declared choices for a choice param; a color param — one whose default is a hex literal — takes '#rrggbb', '#rgb' or a basic CSS colour name and is written back as '#rrggbb')."
          },
          "preview": {
            "type": "boolean",
            "description": "S6 edit preview: evaluate the edit in a scratch session and return geometry + requirements-ledger + S1 binding diffs. Writes nothing. Default false (the normal source-edit result)."
          }
        },
        "required": [
          "code",
          "param_name",
          "new_value"
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "description": "Whether the edit applied and re-evaluated cleanly."
          },
          "viewerUrl": {
            "type": "string",
            "description": "Same live Studio link when this edit built a replacement model."
          },
          "viewerError": {
            "type": "string",
            "description": "Viewer provisioning error, independent of edit diagnostics."
          },
          "viewerMode": {
            "type": "string",
            "enum": [
              "hosted"
            ],
            "description": "Hosted mode uses open_in_studio instead of a process-local viewer."
          },
          "viewerHint": {
            "type": "string",
            "description": "How to view the built model in hosted Studio."
          },
          "step": {
            "type": "object",
            "additionalProperties": true,
            "description": "Per-step build validity, volume and paired local PNG paths with a shared iso frame; unavailable snapshots report an error. Not a topology certificate. Omitted on dry runs."
          },
          "sceneSummary": {
            "type": "object",
            "properties": {
              "valid": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "BREP validity, independent of DFM/mechanism/tool success; null if unchecked."
              },
              "volume": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Volume in mm³; assembly parts summed, including overlaps."
              },
              "faceCount": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "BREP faces, summed per assembly part; not mesh triangles."
              },
              "size": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3,
                "description": "Conservative world AABB size [x,y,z] in mm."
              }
            },
            "required": [
              "valid",
              "volume",
              "faceCount",
              "size"
            ],
            "additionalProperties": false
          },
          "new_code": {
            "type": "string",
            "description": "Modified .kcad.ts source (present on success). Caller persists it."
          },
          "binding_name": {
            "type": "string",
            "description": "JS const name bound to the new construct (when one was created)."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Diagnostics from re-evaluating the modified source."
          },
          "error": {
            "type": "string",
            "description": "Failure message (present when ok is false)."
          },
          "preview": {
            "type": "boolean",
            "description": "True when the result came from preview: true (scratch build, nothing written)."
          },
          "geometry": {
            "type": "object",
            "additionalProperties": true,
            "description": "The diff_geometry result for baseline -> revised: { base, revised, bodies, unmatched, summary, diagnostics }. summary carries identical / moved / resized / topologyChanged / unmatched / totalAddedMm3 / totalRemovedMm3 / maxDeviationMm. Absent on a failed preview."
          },
          "requirementsDiff": {
            "type": "object",
            "additionalProperties": true,
            "description": "S2 ledger diff: { ok, changed, summary: { before, after, flipped, marginsShrunk, added, removed }, entries[], flipped[], marginsShrunk[], added[], removed[] }. Each entry has name/source/featureId, optional before/after snapshots (status, measured, limit, margin, message) and { flipped, changed, margin: { before, after, delta, direction: shrink | grow | same | unknown } }."
          },
          "bindings": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "S1 selectors whose bound entity moved or changed: { consumerFeatureId, selectorText, syntax, occurrence, verdict: moved | changed, pairs[{ verdict, reasons, deltas, before?, after? }] }."
          },
          "before": {
            "type": "object",
            "additionalProperties": true,
            "description": "Baseline evaluation summary: { buildOk, exitCode, featureCount, requirementsOk, requirements, diagnostics }."
          },
          "after": {
            "type": "object",
            "additionalProperties": true,
            "description": "Revised evaluation summary: { buildOk, exitCode, featureCount, requirementsOk, requirements, diagnostics }. Check requirementsOk to see whether the edit preserves declared intent."
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "add_feature",
      "description": "Use this when you need to insert a new feature line into a script. Insert a new feature line into a kernelCAD script before the last top-level return statement. Returns the modified code as text plus diagnostics from re-evaluating the result. Side-effect-free. Primitives that accept faceLabels (box, cylinder, extrudeRect, extrudeCircle, extrudePolygon, extrudeRoundedRect) can receive `opts.faceLabels` in the inserted code — use `lookup_api` to see `featureKindFaceLabels` for the full value schema.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The .kcad.ts source code."
          },
          "feature_code": {
            "type": "string",
            "description": "Single-statement source line to insert (e.g. `const hole = cylinder(5, 2).translate(10, 10, -1);`)."
          }
        },
        "required": [
          "code",
          "feature_code"
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "description": "Whether the edit applied and re-evaluated cleanly."
          },
          "viewerUrl": {
            "type": "string",
            "description": "Same live Studio link when this edit built a replacement model."
          },
          "viewerError": {
            "type": "string",
            "description": "Viewer provisioning error, independent of edit diagnostics."
          },
          "viewerMode": {
            "type": "string",
            "enum": [
              "hosted"
            ],
            "description": "Hosted mode uses open_in_studio instead of a process-local viewer."
          },
          "viewerHint": {
            "type": "string",
            "description": "How to view the built model in hosted Studio."
          },
          "step": {
            "type": "object",
            "additionalProperties": true,
            "description": "Per-step build validity, volume and paired local PNG paths with a shared iso frame; unavailable snapshots report an error. Not a topology certificate. Omitted on dry runs."
          },
          "sceneSummary": {
            "type": "object",
            "properties": {
              "valid": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "BREP validity, independent of DFM/mechanism/tool success; null if unchecked."
              },
              "volume": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Volume in mm³; assembly parts summed, including overlaps."
              },
              "faceCount": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "BREP faces, summed per assembly part; not mesh triangles."
              },
              "size": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3,
                "description": "Conservative world AABB size [x,y,z] in mm."
              }
            },
            "required": [
              "valid",
              "volume",
              "faceCount",
              "size"
            ],
            "additionalProperties": false
          },
          "new_code": {
            "type": "string",
            "description": "Modified .kcad.ts source (present on success). Caller persists it."
          },
          "binding_name": {
            "type": "string",
            "description": "JS const name bound to the new construct (when one was created)."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Diagnostics from re-evaluating the modified source."
          },
          "error": {
            "type": "string",
            "description": "Failure message (present when ok is false)."
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "add_surface",
      "description": "Use this when you need an organic, freeform, or swept shape — a body shell, panel, fairing, ergonomic curve, lens, or sculpted form — authored as a NURBS Surface into the user's .kcad.ts, OR when you need to finish surfaces into a watertight solid or taper faces for moldability. One authoring/finishing path, selected by `kind`:\n- 'nurbs' — insert a nurbsSurface(...) / surfaceFromCurves(...) call. Pass either { controls, degree, weights?, knots?, periodic? } for direct construction, OR { section_sketch_ids } for skinning. Weights are honored: supply rational weights to build exact circles/cylinders/spheres/conics (the surface becomes rational); omit weights for a non-rational surface.\n- 'boundary' — insert a surfaceFromBoundary([c1,c2,c3,c4], opts?) call: one NURBS face through 4 boundary Curve3D refs (bottom, right, top, left in loop order; adjacent endpoints must coincide within 1e-6 mm).\n- 'trim' — insert a `<surface>.trimTo(<by>)` or `<surface>.split(<by>)` call. Pass `surface_binding` (the Surface variable name), `by_binding` (the cutter Surface variable name; Shape/Curve3D cutters are deferred to a later slice), and `op: 'trim'` (keep the largest imprinted piece) or `op: 'split'` (return both halves as a `[Surface, Surface]` tuple).\n- 'sew' — insert a `sew([s0, s1, ...], opts?)` call to stitch N surfaces into a closed watertight solid. Pass `surface_bindings` (array of Surface variable names). Use after trim/boundary to close patches into a solid: trim → sew → solid pipeline. Optional `tolerance` (mm, default 1e-6) and `require_closed` (emits feature.surface-sew.open-shell if result is not watertight).\n- 'draft' — insert a `<shape>.draft(angleDeg, { face, neutralPlane?, pullDir? })` call to taper the selected face(s) for mold release. Pass `shape_binding`, `angle_deg` (0–90), and `face` (canonical name, label, or FaceQuery descriptor). Lowering emits feature.draft.failed on invalid geometry.\nThe returned Surface produces no Shape until you chain .thicken(t) or .toShape() (do that via add_feature on the binding name). Returns the modified code + diagnostics. Each kind fails closed on its own missing required params.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "nurbs",
              "boundary",
              "trim",
              "sew",
              "draft"
            ],
            "description": "Which surface-construction or surface-finishing path to use: 'nurbs' | 'boundary' | 'trim' | 'sew' | 'draft'."
          },
          "code": {
            "type": "string",
            "description": "Current .kcad.ts source."
          },
          "controls": {
            "type": "array",
            "description": "kind:'nurbs' — control-point grid for direct construction (controls[u][v] = [x, y, z], mm).",
            "items": {
              "type": "array",
              "items": {
                "type": "array",
                "items": {
                  "type": "number"
                }
              }
            }
          },
          "weights": {
            "type": "array",
            "description": "kind:'nurbs' — optional rational weights, same grid shape as controls. Ignored in slice-1.",
            "items": {
              "type": "array",
              "items": {
                "type": "number"
              }
            }
          },
          "degree": {
            "type": "object",
            "description": "kind:'nurbs' — degrees in U and V; each in [1, nU-1] / [1, nV-1].",
            "properties": {
              "u": {
                "type": "integer",
                "minimum": 1
              },
              "v": {
                "type": "integer",
                "minimum": 1
              }
            },
            "required": [
              "u",
              "v"
            ]
          },
          "knots": {
            "type": "object",
            "description": "kind:'nurbs' — optional explicit knot vectors; missing => clamped uniform inferred.",
            "properties": {
              "u": {
                "type": "array",
                "items": {
                  "type": "number"
                }
              },
              "v": {
                "type": "array",
                "items": {
                  "type": "number"
                }
              }
            }
          },
          "periodic": {
            "type": "object",
            "description": "kind:'nurbs' — optional periodic flags per parametric direction.",
            "properties": {
              "u": {
                "type": "boolean"
              },
              "v": {
                "type": "boolean"
              }
            }
          },
          "section_sketch_ids": {
            "type": "array",
            "description": "kind:'nurbs' — existing sketch FeatureIds (2 or more) to skin a surface through, in order.",
            "items": {
              "type": "string"
            }
          },
          "curve_bindings": {
            "type": "array",
            "description": "kind:'boundary' — tuple of 4 existing Curve3D variable names (bottom, right, top, left) declared earlier in the source.",
            "items": {
              "type": "string"
            },
            "minItems": 4,
            "maxItems": 4
          },
          "continuity": {
            "description": "kind:'boundary' — continuity grade applied to every edge ('C0' | 'C1' | 'C2'), or an array of 4 grades (one per edge, bottom/right/top/left order). Default 'C0'.",
            "oneOf": [
              {
                "type": "string",
                "enum": [
                  "C0",
                  "C1",
                  "C2"
                ]
              },
              {
                "type": "array",
                "items": {
                  "type": "string",
                  "enum": [
                    "C0",
                    "C1",
                    "C2"
                  ]
                },
                "minItems": 4,
                "maxItems": 4
              }
            ]
          },
          "sampling": {
            "type": "integer",
            "minimum": 1,
            "description": "kind:'boundary' — points sampled along each boundary (default 15)."
          },
          "binding_name": {
            "type": "string",
            "description": "JS const name for the new binding (kind:'nurbs' default surface_<N>; kind:'boundary' default _surface_<N>; kind:'trim' default _trimmed_<N>; kind:'sew' default _sewn_<N>; kind:'draft' default _drafted_<N>)."
          },
          "surface_binding": {
            "type": "string",
            "description": "kind:'trim' — JS variable name of the Surface to trim/split (must be declared in source)."
          },
          "by_binding": {
            "type": "string",
            "description": "kind:'trim' — JS variable name of the cutter Surface (must be declared in source). Shape/Curve3D cutters are deferred."
          },
          "op": {
            "type": "string",
            "enum": [
              "trim",
              "split"
            ],
            "description": "kind:'trim' — 'trim' discards the smaller half (calls .trimTo()); 'split' retains both halves (calls .split())."
          },
          "surface_bindings": {
            "type": "array",
            "description": "kind:'sew' — JS variable names of the surfaces to stitch into a solid (each must be declared in source).",
            "items": {
              "type": "string"
            },
            "minItems": 1
          },
          "tolerance": {
            "type": "number",
            "description": "kind:'sew' — edge-merging tolerance in mm (default 1e-6). Edges within this distance are merged."
          },
          "require_closed": {
            "type": "boolean",
            "description": "kind:'sew' — when true the lowerer emits feature.surface-sew.open-shell if the stitched result is not a watertight solid."
          },
          "shape_binding": {
            "type": "string",
            "description": "kind:'draft' — JS variable name of the Shape to taper (must be declared in source)."
          },
          "angle_deg": {
            "type": "number",
            "minimum": 0,
            "maximum": 90,
            "description": "kind:'draft' — draft angle in degrees [0, 90]. The face is tapered outward by this angle relative to the pull direction."
          },
          "face": {
            "type": "string",
            "description": "kind:'draft' — face selector for the face(s) to taper. Accepts a canonical name (top/bottom/front/back/left/right), a user label declared via faceLabels, or a FaceQuery descriptor string."
          },
          "neutral_plane": {
            "type": "string",
            "description": "kind:'draft' — parting-line face (the plane where drafted faces remain fixed). Defaults to `face` if omitted."
          },
          "pull_dir": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "minItems": 3,
            "maxItems": 3,
            "description": "kind:'draft' — demoulding direction as [x, y, z]. Defaults to the face normal at lower time."
          }
        },
        "required": [
          "kind",
          "code"
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "description": "Whether the edit applied and re-evaluated cleanly."
          },
          "viewerUrl": {
            "type": "string",
            "description": "Same live Studio link when this edit built a replacement model."
          },
          "viewerError": {
            "type": "string",
            "description": "Viewer provisioning error, independent of edit diagnostics."
          },
          "viewerMode": {
            "type": "string",
            "enum": [
              "hosted"
            ],
            "description": "Hosted mode uses open_in_studio instead of a process-local viewer."
          },
          "viewerHint": {
            "type": "string",
            "description": "How to view the built model in hosted Studio."
          },
          "step": {
            "type": "object",
            "additionalProperties": true,
            "description": "Per-step build validity, volume and paired local PNG paths with a shared iso frame; unavailable snapshots report an error. Not a topology certificate. Omitted on dry runs."
          },
          "sceneSummary": {
            "type": "object",
            "properties": {
              "valid": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "BREP validity, independent of DFM/mechanism/tool success; null if unchecked."
              },
              "volume": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Volume in mm³; assembly parts summed, including overlaps."
              },
              "faceCount": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "BREP faces, summed per assembly part; not mesh triangles."
              },
              "size": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3,
                "description": "Conservative world AABB size [x,y,z] in mm."
              }
            },
            "required": [
              "valid",
              "volume",
              "faceCount",
              "size"
            ],
            "additionalProperties": false
          },
          "new_code": {
            "type": "string",
            "description": "Modified .kcad.ts source (present on success). Caller persists it."
          },
          "binding_name": {
            "type": "string",
            "description": "JS const name bound to the new construct (when one was created)."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Diagnostics from re-evaluating the modified source."
          },
          "error": {
            "type": "string",
            "description": "Failure message (present when ok is false)."
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "add_curve",
      "description": "Use this when you need a freeform/organic 3D curve — a body feature line, brow, spine rail, or G2 blend between panels — authored as a Curve3D into the user's .kcad.ts immediately before the last top-level return. One authoring path, selected by `kind`:\n- 'nurbs' — insert a `nurbsCurve(controlPoints, opts?)` declaration. Pass `controlPoints` as a Vec3[] (mm, at least 2 points). Optional NURBS knobs: `degree` (default 3), rational `weights`, explicit `knots`, `closed`.\n- 'hermite' — insert a `hermiteG2(a, b)` declaration: a quintic Hermite curve interpolating two endpoints with matching positions, tangents, and (optional) curvatures — bridges two curves with G2 continuity. Each endpoint is `{ point: Vec3, tangent: Vec3, curvature?: Vec3 }` in mm; tangent magnitude ~ chord length; curvature defaults to [0,0,0] (G1-only).\nThe returned binding has type Curve3D (peer to Shape / Surface) — consume it via `add_variable_sweep` (spine input), `add_surface({ kind: 'boundary' })` (boundary curve), or downstream Curve3D-accepting features. Returns the modified code + diagnostics from re-evaluating. Side-effect-free. Each kind fails closed on its own missing required params.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "nurbs",
              "hermite"
            ],
            "description": "Which curve-construction path to use."
          },
          "code": {
            "type": "string",
            "description": "The .kcad.ts source code."
          },
          "controlPoints": {
            "type": "array",
            "description": "kind:'nurbs' — control points as Vec3 triples in mm; at least 2 entries.",
            "items": {
              "type": "array",
              "items": {
                "type": "number"
              },
              "minItems": 3,
              "maxItems": 3
            }
          },
          "degree": {
            "type": "integer",
            "minimum": 1,
            "description": "kind:'nurbs' — curve degree; default 3 (cubic)."
          },
          "weights": {
            "type": "array",
            "description": "kind:'nurbs' — optional rational weights, one per control point (same length as controlPoints).",
            "items": {
              "type": "number"
            }
          },
          "knots": {
            "type": "array",
            "description": "kind:'nurbs' — optional explicit knot vector; missing => clamped-uniform inferred.",
            "items": {
              "type": "number"
            }
          },
          "closed": {
            "type": "boolean",
            "description": "kind:'nurbs' — optional periodic/closed-curve flag."
          },
          "a": {
            "type": "object",
            "description": "kind:'hermite' — start endpoint.",
            "properties": {
              "point": {
                "type": "array",
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3,
                "description": "Endpoint position in mm."
              },
              "tangent": {
                "type": "array",
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3,
                "description": "First derivative of the curve at this endpoint."
              },
              "curvature": {
                "type": "array",
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3,
                "description": "Optional second derivative; defaults to [0, 0, 0] (G1-only)."
              }
            },
            "required": [
              "point",
              "tangent"
            ]
          },
          "b": {
            "type": "object",
            "description": "kind:'hermite' — end endpoint.",
            "properties": {
              "point": {
                "type": "array",
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3
              },
              "tangent": {
                "type": "array",
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3
              },
              "curvature": {
                "type": "array",
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3
              }
            },
            "required": [
              "point",
              "tangent"
            ]
          },
          "binding_name": {
            "type": "string",
            "description": "JS const name for the new Curve3D binding (default: _curve_<N>)."
          }
        },
        "required": [
          "kind",
          "code"
        ],
        "allOf": [
          {
            "if": {
              "properties": {
                "kind": {
                  "const": "nurbs"
                }
              }
            },
            "then": {
              "required": [
                "controlPoints"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "kind": {
                  "const": "hermite"
                }
              }
            },
            "then": {
              "required": [
                "a",
                "b"
              ]
            }
          }
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "description": "Whether the edit applied and re-evaluated cleanly."
          },
          "viewerUrl": {
            "type": "string",
            "description": "Same live Studio link when this edit built a replacement model."
          },
          "viewerError": {
            "type": "string",
            "description": "Viewer provisioning error, independent of edit diagnostics."
          },
          "viewerMode": {
            "type": "string",
            "enum": [
              "hosted"
            ],
            "description": "Hosted mode uses open_in_studio instead of a process-local viewer."
          },
          "viewerHint": {
            "type": "string",
            "description": "How to view the built model in hosted Studio."
          },
          "step": {
            "type": "object",
            "additionalProperties": true,
            "description": "Per-step build validity, volume and paired local PNG paths with a shared iso frame; unavailable snapshots report an error. Not a topology certificate. Omitted on dry runs."
          },
          "sceneSummary": {
            "type": "object",
            "properties": {
              "valid": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "BREP validity, independent of DFM/mechanism/tool success; null if unchecked."
              },
              "volume": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Volume in mm³; assembly parts summed, including overlaps."
              },
              "faceCount": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "BREP faces, summed per assembly part; not mesh triangles."
              },
              "size": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3,
                "description": "Conservative world AABB size [x,y,z] in mm."
              }
            },
            "required": [
              "valid",
              "volume",
              "faceCount",
              "size"
            ],
            "additionalProperties": false
          },
          "new_code": {
            "type": "string",
            "description": "Modified .kcad.ts source (present on success). Caller persists it."
          },
          "binding_name": {
            "type": "string",
            "description": "JS const name bound to the new construct (when one was created)."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Diagnostics from re-evaluating the modified source."
          },
          "error": {
            "type": "string",
            "description": "Failure message (present when ok is false)."
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "add_path_segment",
      "description": "Use this when you need a freeform/organic 2D outline — an eyewear brow, ergonomic grip, sneaker midsole, or body silhouette — by appending a curved segment to an existing PathBuilder chain on the named `chain_anchor` variable. The call is injected at the END of the chain, immediately before any `.close()`. One segment kind, selected by `kind`:\n- 'spline' — `.spline(points, opts?)`: interpolates through every `points` waypoint (Vec2[] mm, >= 2 entries; points[0] must match current pen position). Optional `tension`, and `startTangent`/`endTangent` 2D direction vectors that constrain the first-derivative direction at the endpoints (magnitude normalised internally). Use for organic 2D outlines (eyewear brow, ergonomic handle, sneaker midsole).\n- 'nurbs' — `.nurbsSegment(controlPoints, opts?)`: explicit B-spline net (Vec2[] mm, >= degree+1 entries; controlPoints[0] must match pen; pen ends at controlPoints[N-1]). Optional `degree` (default 3), rational `weights` (strictly positive), explicit `knots` (length = controlPoints.length + degree + 1).\n- 'hermite' — `.hermiteG2(a, b)`: each endpoint `{ point: Vec2, tangent: Vec2, curvature?: Vec2 }` in mm (a.point must match pen; pen ends at b.point). `curvature` defaults to [0,0] (G1); pass matching curvatures for G2 blends. Tangent magnitude is the first derivative (~ chord length), NOT unit length.\nReturns the modified code + diagnostics from re-evaluating. Side-effect-free. Each kind fails closed on its own missing required params.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "spline",
              "nurbs",
              "hermite"
            ],
            "description": "Which path-segment kind to append."
          },
          "code": {
            "type": "string",
            "description": "The .kcad.ts source code."
          },
          "chain_anchor": {
            "type": "string",
            "description": "JS identifier of an existing PathBuilder binding (e.g. `const brow = path().moveTo(0,0)`)."
          },
          "points": {
            "type": "array",
            "description": "kind:'spline' — waypoints as Vec2 pairs in mm; at least 2 entries; first must match current pen position.",
            "items": {
              "type": "array",
              "items": {
                "type": "number"
              },
              "minItems": 2,
              "maxItems": 2
            },
            "minItems": 2
          },
          "tension": {
            "type": "number",
            "description": "kind:'spline' — optional Catmull-Rom-style stiffness; forwarded to the underlying B-spline approximation."
          },
          "startTangent": {
            "type": "array",
            "description": "kind:'spline' — optional [x, y] direction vector at points[0]. Magnitude is normalised internally; direction matters.",
            "items": {
              "type": "number"
            },
            "minItems": 2,
            "maxItems": 2
          },
          "endTangent": {
            "type": "array",
            "description": "kind:'spline' — optional [x, y] direction vector at points[N-1]. Magnitude is normalised internally; direction matters.",
            "items": {
              "type": "number"
            },
            "minItems": 2,
            "maxItems": 2
          },
          "controlPoints": {
            "type": "array",
            "description": "kind:'nurbs' — control-net vertices as Vec2 pairs in mm; at least degree+1 entries.",
            "items": {
              "type": "array",
              "items": {
                "type": "number"
              },
              "minItems": 2,
              "maxItems": 2
            }
          },
          "degree": {
            "type": "integer",
            "minimum": 1,
            "description": "kind:'nurbs' — B-spline degree (default 3)."
          },
          "weights": {
            "type": "array",
            "description": "kind:'nurbs' — optional rational weights (one per control point; strictly positive).",
            "items": {
              "type": "number"
            }
          },
          "knots": {
            "type": "array",
            "description": "kind:'nurbs' — optional explicit knot vector; length must equal controlPoints.length + degree + 1.",
            "items": {
              "type": "number"
            }
          },
          "a": {
            "type": "object",
            "description": "kind:'hermite' — start endpoint; point must match current pen position within 1e-6 mm.",
            "properties": {
              "point": {
                "type": "array",
                "items": {
                  "type": "number"
                },
                "minItems": 2,
                "maxItems": 2
              },
              "tangent": {
                "type": "array",
                "items": {
                  "type": "number"
                },
                "minItems": 2,
                "maxItems": 2
              },
              "curvature": {
                "type": "array",
                "items": {
                  "type": "number"
                },
                "minItems": 2,
                "maxItems": 2
              }
            },
            "required": [
              "point",
              "tangent"
            ]
          },
          "b": {
            "type": "object",
            "description": "kind:'hermite' — end endpoint.",
            "properties": {
              "point": {
                "type": "array",
                "items": {
                  "type": "number"
                },
                "minItems": 2,
                "maxItems": 2
              },
              "tangent": {
                "type": "array",
                "items": {
                  "type": "number"
                },
                "minItems": 2,
                "maxItems": 2
              },
              "curvature": {
                "type": "array",
                "items": {
                  "type": "number"
                },
                "minItems": 2,
                "maxItems": 2
              }
            },
            "required": [
              "point",
              "tangent"
            ]
          },
          "binding_name": {
            "type": "string",
            "description": "Reserved for future use; the segment injection mutates the chain anchor in place."
          }
        },
        "required": [
          "kind",
          "code",
          "chain_anchor"
        ],
        "allOf": [
          {
            "if": {
              "properties": {
                "kind": {
                  "const": "spline"
                }
              }
            },
            "then": {
              "required": [
                "points"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "kind": {
                  "const": "nurbs"
                }
              }
            },
            "then": {
              "required": [
                "controlPoints"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "kind": {
                  "const": "hermite"
                }
              }
            },
            "then": {
              "required": [
                "a",
                "b"
              ]
            }
          }
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "description": "Whether the edit applied and re-evaluated cleanly."
          },
          "viewerUrl": {
            "type": "string",
            "description": "Same live Studio link when this edit built a replacement model."
          },
          "viewerError": {
            "type": "string",
            "description": "Viewer provisioning error, independent of edit diagnostics."
          },
          "viewerMode": {
            "type": "string",
            "enum": [
              "hosted"
            ],
            "description": "Hosted mode uses open_in_studio instead of a process-local viewer."
          },
          "viewerHint": {
            "type": "string",
            "description": "How to view the built model in hosted Studio."
          },
          "step": {
            "type": "object",
            "additionalProperties": true,
            "description": "Per-step build validity, volume and paired local PNG paths with a shared iso frame; unavailable snapshots report an error. Not a topology certificate. Omitted on dry runs."
          },
          "sceneSummary": {
            "type": "object",
            "properties": {
              "valid": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "BREP validity, independent of DFM/mechanism/tool success; null if unchecked."
              },
              "volume": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Volume in mm³; assembly parts summed, including overlaps."
              },
              "faceCount": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "BREP faces, summed per assembly part; not mesh triangles."
              },
              "size": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3,
                "description": "Conservative world AABB size [x,y,z] in mm."
              }
            },
            "required": [
              "valid",
              "volume",
              "faceCount",
              "size"
            ],
            "additionalProperties": false
          },
          "new_code": {
            "type": "string",
            "description": "Modified .kcad.ts source (present on success). Caller persists it."
          },
          "binding_name": {
            "type": "string",
            "description": "JS const name bound to the new construct (when one was created)."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Diagnostics from re-evaluating the modified source."
          },
          "error": {
            "type": "string",
            "description": "Failure message (present when ok is false)."
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "trace_from_image",
      "description": "Use this when you need to trace a reference image into normalized waypoints. Trace pixel-space features from a reference photo into normalized [0..1] waypoints the agent can map to mm via a known scale anchor and feed to path().spline / path().nurbsSegment. Three backends are dispatched behind the scenes: `opencv` (deterministic; uniform-bg silhouette only), `vision-llm` (vision model; named points/cluttered backgrounds; needs a configured vision endpoint), and `hybrid` (opencv silhouette + LLM-labeled named points). Default backend is `auto`. Per-feature confidence is reported. Pair with the `kernelcad-trace-from-image` skill for the conversion-to-mm pipeline.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "imageUrl": {
            "type": "string",
            "description": "URL or path to the reference image. Supports file://, http(s)://, data:image/...;base64,..., or a bare filesystem path."
          },
          "hint": {
            "type": "string",
            "description": "Optional free-text hint forwarded to vision-LLM backends (e.g. \"a pair of eyewear; trace the upper brow only\")."
          },
          "features": {
            "type": "array",
            "description": "Features to trace. Defaults to a single { label: \"silhouette\", kind: \"silhouette\" } when omitted.",
            "items": {
              "type": "object",
              "properties": {
                "label": {
                  "type": "string",
                  "description": "Caller-chosen identifier (echoed in the response)."
                },
                "kind": {
                  "type": "string",
                  "enum": [
                    "silhouette",
                    "curve",
                    "point",
                    "bbox"
                  ],
                  "description": "Geometric shape of the requested feature."
                },
                "region": {
                  "type": "string",
                  "description": "Optional free-text region hint forwarded to vision-LLM backends; ignored by opencv."
                }
              },
              "required": [
                "label",
                "kind"
              ]
            }
          },
          "maxWaypointsPerFeature": {
            "type": "integer",
            "description": "Cap on waypoints per feature. Defaults to 12 (suitable for medium-inflection outlines).",
            "minimum": 2
          },
          "backend": {
            "type": "string",
            "enum": [
              "opencv",
              "vision-llm",
              "hybrid",
              "auto"
            ],
            "description": "Force a specific backend; default `auto` routes by corner-color stddev."
          },
          "scaleAnchor": {
            "type": "object",
            "description": "Pixel-to-real-world scale anchor: two measured points on the image. Absent -> the returned ledger's `scale` fact is `missing`.",
            "properties": {
              "pixelDistance": {
                "type": "number",
                "description": "Distance in pixels between the two measured points."
              },
              "realDistance": {
                "type": "number",
                "description": "The same distance in real-world units."
              },
              "unit": {
                "type": "string",
                "enum": [
                  "mm",
                  "cm",
                  "in"
                ]
              }
            },
            "required": [
              "pixelDistance",
              "realDistance",
              "unit"
            ]
          },
          "priors": {
            "type": "array",
            "description": "Caller-supplied category-norm defaults (e.g. wall thickness) recorded verbatim as `assumed` ledger facts.",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "statement": {
                  "type": "string"
                },
                "value": {
                  "type": [
                    "string",
                    "number",
                    "boolean",
                    "array",
                    "object"
                  ]
                },
                "confidence": {
                  "type": "number",
                  "minimum": 0,
                  "maximum": 1
                }
              },
              "required": [
                "id",
                "statement",
                "value",
                "confidence"
              ]
            }
          },
          "validate": {
            "type": "string",
            "enum": [
              "warn",
              "error"
            ],
            "description": "Assumption-ledger strictness. `warn` (default) never blocks. `error` fails the call when any `missing` ledger fact (e.g. scale) is still open."
          }
        },
        "required": [
          "imageUrl"
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": true
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "features": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Traced features with normalized [0..1] waypoints + confidence."
          },
          "imageDims": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "description": "Pixel dimensions [width, height] of the source image."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "ledger": {
            "type": "object",
            "additionalProperties": true,
            "description": "Assumption ledger: { facts, scale?, unresolvedCount } classifying every fact as visible/inferred/assumed/missing."
          }
        },
        "required": [
          "ok",
          "features",
          "imageDims",
          "diagnostics",
          "ledger"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "add_variable_sweep",
      "description": "Use this when you need an organic swept solid whose cross-section changes along its length — a tapering body, horn, bottle, handle, ring band, fairing, or duct — authored as a variable-section sweep along a spine. Inserts `variableSweep(spine, sections, opts?)` into the .kcad.ts `code` immediately before the last top-level return (an empty `code` starts a new script that returns the sweep). Spine: EITHER `spine_points` ([[x,y,z], ...] in mm, interpolated with spline3d; `spine_closed: true` closes the loop for a ring) OR `spine_binding` (an existing Curve3D / Sketch / Vec3[] variable). Each section: `t` in [0, 1] plus a profile — inline `radius` (circle) or `width` + `height` (rectangle), or `profile_binding` (an existing Sketch); profiles are centred on the spine and turned to face along it. Sections are strictly increasing in t, first t=0, last t=1 (omit t on every section to space them evenly). On a closed spine t=1 is the seam and reuses the t=0 profile. Example: { code, spine_points: [[0,0,0],[0,10,30],[0,0,60]], sections: [{ t: 0, radius: 8 }, { t: 0.5, radius: 10 }, { t: 1, radius: 4 }] }. Returns the modified code, diagnostics from re-evaluating it, and `sweep` { volumeMm3, bbox } measured from the built solid (ok:false when the sweep built nothing). The result is a Shape binding: return it, or chain `.union(...)` etc. via add_feature. Orientation is not exposed by this MCP tool until runtime orientation support is wired. Side-effect-free.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The .kcad.ts source code (\"\" for a new script)."
          },
          "spine_points": {
            "type": "array",
            "description": "Inline spine: at least 2 [x, y, z] points in mm, interpolated with spline3d. Use this OR spine_binding.",
            "items": {
              "type": "array",
              "items": {
                "type": "number"
              },
              "minItems": 3,
              "maxItems": 3
            }
          },
          "spine_closed": {
            "type": "boolean",
            "description": "With spine_points: close the spline into a loop (ring band, loop handle)."
          },
          "spine_binding": {
            "type": "string",
            "description": "Existing variable name for a Curve3D / Sketch / Vec3[] declared earlier in the source. Use this OR spine_points."
          },
          "sections": {
            "type": "array",
            "description": "Varying cross-sections along the spine; at least 2 entries, strictly increasing in `t`, first t=0, last t=1.",
            "items": {
              "type": "object",
              "properties": {
                "t": {
                  "type": "number",
                  "description": "Spine parameter in [0, 1]."
                },
                "radius": {
                  "type": "number",
                  "description": "Inline circular profile radius, mm."
                },
                "width": {
                  "type": "number",
                  "description": "Inline rectangular profile width, mm (with height)."
                },
                "height": {
                  "type": "number",
                  "description": "Inline rectangular profile height, mm (with width)."
                },
                "profile_binding": {
                  "type": "string",
                  "description": "Existing Sketch variable name for this section (instead of radius / width+height)."
                }
              }
            }
          },
          "closed": {
            "type": "boolean",
            "description": "Optional closed-sweep flag."
          },
          "continuity": {
            "type": "string",
            "enum": [
              "C0",
              "C1",
              "C2"
            ],
            "description": "Inter-section continuity; default 'C1'."
          },
          "binding_name": {
            "type": "string",
            "description": "JS const name for the new Shape binding (default: _sweep_<N>)."
          }
        },
        "required": [
          "code",
          "sections"
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "description": "Whether the edit applied and re-evaluated cleanly."
          },
          "viewerUrl": {
            "type": "string",
            "description": "Same live Studio link when this edit built a replacement model."
          },
          "viewerError": {
            "type": "string",
            "description": "Viewer provisioning error, independent of edit diagnostics."
          },
          "viewerMode": {
            "type": "string",
            "enum": [
              "hosted"
            ],
            "description": "Hosted mode uses open_in_studio instead of a process-local viewer."
          },
          "viewerHint": {
            "type": "string",
            "description": "How to view the built model in hosted Studio."
          },
          "step": {
            "type": "object",
            "additionalProperties": true,
            "description": "Per-step build validity, volume and paired local PNG paths with a shared iso frame; unavailable snapshots report an error. Not a topology certificate. Omitted on dry runs."
          },
          "sceneSummary": {
            "type": "object",
            "properties": {
              "valid": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "BREP validity, independent of DFM/mechanism/tool success; null if unchecked."
              },
              "volume": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Volume in mm³; assembly parts summed, including overlaps."
              },
              "faceCount": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "BREP faces, summed per assembly part; not mesh triangles."
              },
              "size": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3,
                "description": "Conservative world AABB size [x,y,z] in mm."
              }
            },
            "required": [
              "valid",
              "volume",
              "faceCount",
              "size"
            ],
            "additionalProperties": false
          },
          "new_code": {
            "type": "string",
            "description": "Modified .kcad.ts source (present on success). Caller persists it."
          },
          "binding_name": {
            "type": "string",
            "description": "JS const name bound to the new construct (when one was created)."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Diagnostics from re-evaluating the modified source."
          },
          "error": {
            "type": "string",
            "description": "Failure message (present when ok is false)."
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "add_text",
      "description": "Use this when you need to author text into a kernelCAD script before the last top-level return. One authoring path, selected by `mode`:\n- 'sketch' — insert a sketch.text(...) call. The emitted sketch is chainable: pair with subsequent .extrude(...) / cut(...) edits to land an engraved or raised text feature.\n- 'emboss' — insert a `<shape>.embossText({...})` chained call onto an existing Shape `target`. Use for engraved brand text on faces (Ray-Ban temple, CE mark, model number). `depth > 0` raises text out of the face; `depth < 0` engraves text into the face. Lowers via replicad drawText → sketchOnFace → extrude → fuse|cut.\nDefault font is the runtime-bundled Liberation Sans. Side-effect-free; returns the modified code plus diagnostics from re-evaluating. Each mode fails closed on its own missing required params.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "sketch",
              "emboss"
            ],
            "description": "Which text-authoring path to use."
          },
          "code": {
            "type": "string",
            "description": "The .kcad.ts source code."
          },
          "content": {
            "type": "string",
            "description": "mode:'sketch' — text content (UTF-8, non-empty, non-whitespace)."
          },
          "size": {
            "type": "number",
            "description": "mode:'sketch'|'emboss' — glyph cap height in mm (positive finite)."
          },
          "font": {
            "type": "string",
            "description": "mode:'sketch' — optional logical font name or .ttf file path; defaults to bundled Liberation Sans."
          },
          "align": {
            "type": "string",
            "enum": [
              "left",
              "center",
              "right"
            ],
            "description": "mode:'sketch' — horizontal alignment relative to position (default left); mode:'emboss' — relative to the UV anchor (default center)."
          },
          "position": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "minItems": 2,
            "maxItems": 2,
            "description": "mode:'sketch' — [x, y] anchor in mm. Default [0, 0]."
          },
          "rotation": {
            "type": "number",
            "description": "mode:'sketch' — CCW rotation in degrees around position (default 0); mode:'emboss' — CCW rotation in the face tangent plane (default 0)."
          },
          "bindAs": {
            "type": "string",
            "description": "mode:'sketch' — emits `const <bindAs> = sketch.text(...)`; mode:'emboss' — emits `const <bindAs> = <target>.embossText(...);`."
          },
          "target": {
            "type": "string",
            "description": "mode:'emboss' — variable name of the Shape to chain onto (inserted verbatim)."
          },
          "textContent": {
            "type": "string",
            "description": "mode:'emboss' — text content (UTF-8, non-empty, non-whitespace)."
          },
          "depth": {
            "type": "number",
            "description": "mode:'emboss' — signed extrusion depth in mm: positive emboss out, negative engrave in. Must be non-zero."
          },
          "face": {
            "type": "string",
            "description": "mode:'emboss' — target face — canonical name ('top'/'bottom'/'left'/'right'/'front'/'back') or label."
          },
          "fontFamily": {
            "type": "string",
            "description": "mode:'emboss' — optional logical font name or .ttf file path; defaults to bundled Liberation Sans."
          },
          "anchorU": {
            "type": "number",
            "description": "mode:'emboss' — U anchor in [0, 1] face-local (0=umin, 0.5=centre, 1=umax). Default 0.5."
          },
          "anchorV": {
            "type": "number",
            "description": "mode:'emboss' — V anchor in [0, 1] face-local. Default 0.5."
          },
          "scaleMode": {
            "type": "string",
            "enum": [
              "original",
              "native",
              "bounds"
            ],
            "description": "mode:'emboss' — Drawing.sketchOnFace scaling mode. Default original."
          }
        },
        "required": [
          "mode",
          "code"
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "description": "Whether the edit applied and re-evaluated cleanly."
          },
          "viewerUrl": {
            "type": "string",
            "description": "Same live Studio link when this edit built a replacement model."
          },
          "viewerError": {
            "type": "string",
            "description": "Viewer provisioning error, independent of edit diagnostics."
          },
          "viewerMode": {
            "type": "string",
            "enum": [
              "hosted"
            ],
            "description": "Hosted mode uses open_in_studio instead of a process-local viewer."
          },
          "viewerHint": {
            "type": "string",
            "description": "How to view the built model in hosted Studio."
          },
          "step": {
            "type": "object",
            "additionalProperties": true,
            "description": "Per-step build validity, volume and paired local PNG paths with a shared iso frame; unavailable snapshots report an error. Not a topology certificate. Omitted on dry runs."
          },
          "sceneSummary": {
            "type": "object",
            "properties": {
              "valid": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "BREP validity, independent of DFM/mechanism/tool success; null if unchecked."
              },
              "volume": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Volume in mm³; assembly parts summed, including overlaps."
              },
              "faceCount": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "BREP faces, summed per assembly part; not mesh triangles."
              },
              "size": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3,
                "description": "Conservative world AABB size [x,y,z] in mm."
              }
            },
            "required": [
              "valid",
              "volume",
              "faceCount",
              "size"
            ],
            "additionalProperties": false
          },
          "new_code": {
            "type": "string",
            "description": "Modified .kcad.ts source (present on success). Caller persists it."
          },
          "binding_name": {
            "type": "string",
            "description": "JS const name bound to the new construct (when one was created)."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Diagnostics from re-evaluating the modified source."
          },
          "error": {
            "type": "string",
            "description": "Failure message (present when ok is false)."
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "project_curve",
      "description": "Use this when you need to wrap a 2D closed curve onto a 3D face. Insert a `<shape>.projectCurve({ source, face, scaleMode? })` chained call into a kernelCAD script. The `source` is the structured `{ kind: \"sketchCommands\", commands: [...] }` wire format the runtime API accepts. Wraps the curve onto the face along the face normal; pair with `.extrude(d)` / `.cut(...)` for raised or engraved logos on curved bodies. Open-wire projection (`asEdge: true`) is not implemented and is rejected at edit time. Side-effect-free; returns modified code plus diagnostics.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The .kcad.ts source code."
          },
          "target": {
            "type": "string",
            "description": "Variable name of the Shape to chain onto."
          },
          "commands": {
            "type": "array",
            "description": "Closed 2D path to wrap onto the face, as plain-number commands. Must start with a `moveTo` and end with a `close` (e.g. [{kind:\"moveTo\",x:0,y:0},{kind:\"lineTo\",x:2,y:0},{kind:\"lineTo\",x:2,y:2},{kind:\"close\"}]).",
            "items": {
              "type": "object",
              "properties": {
                "kind": {
                  "type": "string",
                  "enum": [
                    "moveTo",
                    "lineTo",
                    "close"
                  ]
                },
                "x": {
                  "type": "number"
                },
                "y": {
                  "type": "number"
                }
              },
              "required": [
                "kind"
              ]
            }
          },
          "face": {
            "type": "string",
            "description": "Target face — canonical name or label."
          },
          "scaleMode": {
            "type": "string",
            "enum": [
              "original",
              "native",
              "bounds"
            ],
            "description": "Drawing.sketchOnFace scaling mode. Default original."
          },
          "asEdge": {
            "type": "boolean",
            "description": "Open-wire (edge) projection. NOT IMPLEMENTED — rejected at edit time. Use a closed-curve projection (omit asEdge)."
          },
          "bindAs": {
            "type": "string",
            "description": "Optional local variable name; emits `const <bindAs> = <target>.projectCurve(...);`."
          }
        },
        "required": [
          "code",
          "target",
          "commands",
          "face"
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "description": "Whether the edit applied and re-evaluated cleanly."
          },
          "viewerUrl": {
            "type": "string",
            "description": "Same live Studio link when this edit built a replacement model."
          },
          "viewerError": {
            "type": "string",
            "description": "Viewer provisioning error, independent of edit diagnostics."
          },
          "viewerMode": {
            "type": "string",
            "enum": [
              "hosted"
            ],
            "description": "Hosted mode uses open_in_studio instead of a process-local viewer."
          },
          "viewerHint": {
            "type": "string",
            "description": "How to view the built model in hosted Studio."
          },
          "step": {
            "type": "object",
            "additionalProperties": true,
            "description": "Per-step build validity, volume and paired local PNG paths with a shared iso frame; unavailable snapshots report an error. Not a topology certificate. Omitted on dry runs."
          },
          "sceneSummary": {
            "type": "object",
            "properties": {
              "valid": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "BREP validity, independent of DFM/mechanism/tool success; null if unchecked."
              },
              "volume": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Volume in mm³; assembly parts summed, including overlaps."
              },
              "faceCount": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "BREP faces, summed per assembly part; not mesh triangles."
              },
              "size": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3,
                "description": "Conservative world AABB size [x,y,z] in mm."
              }
            },
            "required": [
              "valid",
              "volume",
              "faceCount",
              "size"
            ],
            "additionalProperties": false
          },
          "new_code": {
            "type": "string",
            "description": "Modified .kcad.ts source (present on success). Caller persists it."
          },
          "binding_name": {
            "type": "string",
            "description": "JS const name bound to the new construct (when one was created)."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Diagnostics from re-evaluating the modified source."
          },
          "error": {
            "type": "string",
            "description": "Failure message (present when ok is false)."
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "add_pattern_feature",
      "description": "Use this when you need to repeat a feature in a pattern. Insert a Shape.patternLinear / .patternCircular / .patternGrid call into a kernelCAD script before the last top-level return. Pass structured args (kind + the matching spec object). Returns the modified code plus diagnostics from re-evaluating. Side-effect-free. The pattern feature is a single editable unit; pattern-instance face refs resolve via `<sourceId>_pattern_<i>` on the pattern feature's lineage. Geometric note: pattern is implemented as cumulative boolean union of transformed source copies — additive features (boxes, ribs, fins, spokes) pattern cleanly; patterning a subtractive feature (hole, cutout) only preserves the per-instance void when adjacent bodies are disjoint.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The .kcad.ts source code."
          },
          "target": {
            "type": "string",
            "description": "Variable name of the Shape to pattern (inserted verbatim as the LHS receiver)."
          },
          "kind": {
            "type": "string",
            "enum": [
              "linear",
              "circular",
              "grid"
            ]
          },
          "linear": {
            "type": "object",
            "description": "Required when kind=linear.",
            "properties": {
              "count": {
                "type": "integer",
                "minimum": 2
              },
              "direction": {
                "type": "array",
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3
              },
              "spacing": {
                "type": "number"
              }
            },
            "required": [
              "count",
              "direction",
              "spacing"
            ]
          },
          "circular": {
            "type": "object",
            "description": "Required when kind=circular.",
            "properties": {
              "count": {
                "type": "integer",
                "minimum": 2
              },
              "axis": {
                "type": "array",
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3
              },
              "angleDeg": {
                "type": "number",
                "description": "Optional; defaults to 360."
              }
            },
            "required": [
              "count",
              "axis"
            ]
          },
          "grid": {
            "type": "object",
            "description": "Required when kind=grid.",
            "properties": {
              "x": {
                "type": "object",
                "description": "First grid axis.",
                "properties": {
                  "count": {
                    "type": "integer",
                    "minimum": 2
                  },
                  "direction": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    },
                    "minItems": 3,
                    "maxItems": 3
                  },
                  "spacing": {
                    "type": "number"
                  }
                },
                "required": [
                  "count",
                  "direction",
                  "spacing"
                ]
              },
              "y": {
                "type": "object",
                "description": "Second grid axis.",
                "properties": {
                  "count": {
                    "type": "integer",
                    "minimum": 2
                  },
                  "direction": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    },
                    "minItems": 3,
                    "maxItems": 3
                  },
                  "spacing": {
                    "type": "number"
                  }
                },
                "required": [
                  "count",
                  "direction",
                  "spacing"
                ]
              }
            },
            "required": [
              "x",
              "y"
            ]
          },
          "assign_to": {
            "type": "string",
            "description": "Optional const-binding name; emits `const <assign_to> = <target>.patternX(...);`. Omit for statement form."
          }
        },
        "required": [
          "code",
          "target",
          "kind"
        ],
        "allOf": [
          {
            "if": {
              "properties": {
                "kind": {
                  "const": "linear"
                }
              }
            },
            "then": {
              "required": [
                "linear"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "kind": {
                  "const": "circular"
                }
              }
            },
            "then": {
              "required": [
                "circular"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "kind": {
                  "const": "grid"
                }
              }
            },
            "then": {
              "required": [
                "grid"
              ]
            }
          }
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "description": "Whether the edit applied and re-evaluated cleanly."
          },
          "viewerUrl": {
            "type": "string",
            "description": "Same live Studio link when this edit built a replacement model."
          },
          "viewerError": {
            "type": "string",
            "description": "Viewer provisioning error, independent of edit diagnostics."
          },
          "viewerMode": {
            "type": "string",
            "enum": [
              "hosted"
            ],
            "description": "Hosted mode uses open_in_studio instead of a process-local viewer."
          },
          "viewerHint": {
            "type": "string",
            "description": "How to view the built model in hosted Studio."
          },
          "step": {
            "type": "object",
            "additionalProperties": true,
            "description": "Per-step build validity, volume and paired local PNG paths with a shared iso frame; unavailable snapshots report an error. Not a topology certificate. Omitted on dry runs."
          },
          "sceneSummary": {
            "type": "object",
            "properties": {
              "valid": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "BREP validity, independent of DFM/mechanism/tool success; null if unchecked."
              },
              "volume": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Volume in mm³; assembly parts summed, including overlaps."
              },
              "faceCount": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "BREP faces, summed per assembly part; not mesh triangles."
              },
              "size": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3,
                "description": "Conservative world AABB size [x,y,z] in mm."
              }
            },
            "required": [
              "valid",
              "volume",
              "faceCount",
              "size"
            ],
            "additionalProperties": false
          },
          "new_code": {
            "type": "string",
            "description": "Modified .kcad.ts source (present on success). Caller persists it."
          },
          "binding_name": {
            "type": "string",
            "description": "JS const name bound to the new construct (when one was created)."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Diagnostics from re-evaluating the modified source."
          },
          "error": {
            "type": "string",
            "description": "Failure message (present when ok is false)."
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "remove_feature",
      "description": "Use this when you need to remove a feature line from a script. Remove a single line from a kernelCAD script identified by a substring match. Returns the modified code plus diagnostics from re-evaluating. Refuses to remove the line containing the return statement. Side-effect-free.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The .kcad.ts source code."
          },
          "match": {
            "type": "string",
            "description": "A substring that uniquely identifies the line to remove (e.g. `const hole = cylinder(5,`)."
          }
        },
        "required": [
          "code",
          "match"
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "description": "Whether the edit applied and re-evaluated cleanly."
          },
          "viewerUrl": {
            "type": "string",
            "description": "Same live Studio link when this edit built a replacement model."
          },
          "viewerError": {
            "type": "string",
            "description": "Viewer provisioning error, independent of edit diagnostics."
          },
          "viewerMode": {
            "type": "string",
            "enum": [
              "hosted"
            ],
            "description": "Hosted mode uses open_in_studio instead of a process-local viewer."
          },
          "viewerHint": {
            "type": "string",
            "description": "How to view the built model in hosted Studio."
          },
          "step": {
            "type": "object",
            "additionalProperties": true,
            "description": "Per-step build validity, volume and paired local PNG paths with a shared iso frame; unavailable snapshots report an error. Not a topology certificate. Omitted on dry runs."
          },
          "sceneSummary": {
            "type": "object",
            "properties": {
              "valid": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "BREP validity, independent of DFM/mechanism/tool success; null if unchecked."
              },
              "volume": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Volume in mm³; assembly parts summed, including overlaps."
              },
              "faceCount": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "BREP faces, summed per assembly part; not mesh triangles."
              },
              "size": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3,
                "description": "Conservative world AABB size [x,y,z] in mm."
              }
            },
            "required": [
              "valid",
              "volume",
              "faceCount",
              "size"
            ],
            "additionalProperties": false
          },
          "new_code": {
            "type": "string",
            "description": "Modified .kcad.ts source (present on success). Caller persists it."
          },
          "binding_name": {
            "type": "string",
            "description": "JS const name bound to the new construct (when one was created)."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Diagnostics from re-evaluating the modified source."
          },
          "error": {
            "type": "string",
            "description": "Failure message (present when ok is false)."
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "query",
      "description": "Use this when you need to resolve or inspect topology against a script's lowered geometry. Pass the script as `code` (inline; works on a hosted server) or `file`. Selected by `mode` (default 'evaluate'):\n- 'evaluate' — list the faces a Query matches ({ query }). Pass expect:'unique' to assert exactly-one.\n- 'resolve' — resolve one ref to one face ({ ref }).\n- 'lineage' — the creating/modifying history of a face ({ ref }; feature_id defaults to the last feature).\nQuery forms (faces only; edge/vertex kinds return query.unsupported-entity-type):\n- a bare face label: 'top', 'bottom', 'left', 'right', 'front', 'back', or a hole/cutout slot like 'wall'.\n- @kc[<feature-id>/face/<label>] — feature ids are the ones refs print, e.g. '@kc[box_1/face/top]', '@kc[hole_1/face/wall]'.\n- @kcq[face(<filter>, ...)] — filters AND together: createdBy(\"box_1\"), withLabel(\"top\"), geometryType(PLANE|CYLINDER|CONE|SPHERE|TORUS|BSPLINE_SURFACE), closestTo([x,y,z]) or closestTo([x,y,z], k), containsPoint([x,y,z]); combine with union(a, b), intersection(a, b), subtraction(a, b). Example: '@kcq[face(geometryType(CYLINDER), closestTo([0,0,10]))]'.\nEach matched face comes back with its canonical @kc ref, centroid, normal and area.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "evaluate",
              "resolve",
              "lineage"
            ],
            "description": "Resolution mode (default 'evaluate')."
          },
          "file": {
            "type": "string",
            "description": "Path to a .kcad.ts script file."
          },
          "code": {
            "type": "string",
            "description": "Inline kernelCAD script source."
          },
          "query": {
            "type": [
              "string",
              "object"
            ],
            "description": "mode:'evaluate' — Query: a bare face label ('top'), an @kc[<feature-id>/face/<label>] ref, an @kcq[face(...)] expression, or { ast }."
          },
          "ref": {
            "type": "string",
            "description": "mode:'resolve'|'lineage' — one face: '@kc[box_1/face/top]', '@kcq[...]', or '<feature-id>.<label>' (lineage)."
          },
          "expect": {
            "type": "string",
            "enum": [
              "any",
              "unique"
            ],
            "description": "mode:'evaluate' — 'unique' asserts exactly-one."
          },
          "feature_id": {
            "type": "string",
            "description": "Optional FeatureId; defaults to the last lowered shape (use \"auto\" for lineage)."
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "entities": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "mode:'evaluate' — matched entities."
          },
          "query": {
            "type": "object",
            "additionalProperties": true,
            "description": "mode:'evaluate' — the resolved Query ({ ast })."
          },
          "ref": {
            "type": "string",
            "description": "mode:'resolve' — the resolved ref string."
          },
          "entity": {
            "type": "object",
            "additionalProperties": true,
            "description": "mode:'resolve' — the single matched entity."
          },
          "candidates": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "mode:'resolve' — near-miss candidates (failure)."
          },
          "chain": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "mode:'lineage' — HistoryMap walk."
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "error": {
            "type": "string"
          },
          "errorCode": {
            "type": "string"
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "lookup_api",
      "description": "Use this when you need to list the kernelCAD script-runtime surface: global functions (box, path, selectEdges, helix, etc), Shape methods (fillet, sweep, lower, etc), Sketch methods (extrude, revolve, sweep), PathBuilder methods, EdgeQuery/FaceQuery key sets, and featureKindFaceLabels (which globals accept opts.faceLabels and valid value shapes). Use this to discover what is callable from a .kcad.ts script. Call this BEFORE concluding kernelCAD lacks a capability — its NURBS freeform surfacing (loft, sweep, boundary-fill, G2 blend) is easy to miss from tool names alone.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "globals": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "shapeMethods": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "shapeListMethods": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "sketchMethods": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "pathBuilderMethods": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "paramRefMethods": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "sceneMethods": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "scenePartProperties": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "surfaceMethods": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "curve3dMethods": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "curve3dAnalyticsMethods": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "edgeQueryKeys": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "faceQueryKeys": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "featureKindFaceLabels": {
            "type": "object",
            "additionalProperties": true
          },
          "constraints": {
            "type": "object",
            "additionalProperties": true
          },
          "error": {
            "type": "string"
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "lookup_diagnostics",
      "description": "Use this when you need the kernelCAD 26-code diagnostic catalogue with hint templates. Tiny one-shot call; useful for an agent that wants to pre-populate retry strategies. Hints are also inline on every emitted diagnostic — this tool just gives you the canonical list up front.",
      "inputSchema": {
        "type": "object",
        "properties": {}
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "codes": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "The diagnostic-code catalogue with hint templates."
          }
        },
        "required": [
          "ok",
          "codes"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "export",
      "description": "Use this when you need to export geometry to a file. One exporter, selected by `target`:\n- target:'model' — export the script geometry to one file. Pass { file | code }, a required { output_path }, and { format }. Supported formats: stl (binary STL mesh), step (BREP CAD interchange), dxf (2D cut file for laser / waterjet / CNC: a flat part — plate, panel, extruded profile, in any orientation — exports its outline and holes in its own plane with exact arcs and circles; a sheet-metal part or a returned Region exports its flat pattern; a flat or sheet-metal part also returns sheet { thickness_mm, bend_count }, which a shop needs and the DXF does not carry; options.section { axis: \"x\"|\"y\"|\"z\", at } exports the cross-section of any part in world coordinates (plans, profiles); a multi-part model (cut list) writes all parts side by side on output_path, one layer per part, plus parts/<part>.dxf per part (reported in part_files; options.layout 'sheet' writes the combined sheet only); any other part fails with export.dxf.non-planar), 3mf (slicer-friendly mesh: one named object per part, colours as core-spec basematerials named by the part's engineering material; options.arrange 'plate' packs parts on the bed at Z=0 without overlap (options.orient puts each part's largest flat face down), 'assembled' keeps them together as one multi-part object for multi-colour prints; options.slicer 'bambu' | 'orca' | 'prusa' adds that slicer's per-object name + filament-slot sidecar — slot N is the Nth distinct colour/material), options.infill { fromFea: '<study>' | true, bands?, pattern? } = stress-graded FDM infill (requires the local CalculiX + gmsh toolchain; without it the export fails with fea.solver.unavailable): solves the feaStudy and writes modifier volumes, each with its own infill density (Orca/Bambu format by default; options.slicer 'prusa' writes PrusaSlicer's format instead, since the two are not interchangeable); the result carries infill { bands, saving, images }), gcode (installed OrcaSlicer output; preserves G-code and returns optional gcode_stats with header generator identity and slicer-predicted time/material), glb (web-viewer / AR with PBR materials), obj (Wavefront indexed triangle mesh), usd (ASCII USDA triangle mesh in millimeter, Z-up coordinates; multi-part scenes emit one named mesh per part), svg-drawing (third-angle engineering-drawing sheet: front/top/left + isometric views, hidden edges dashed, tangent edges thin, overall bounding-box dimensions, title block; assemblies are drawn with inter-part occlusion; pass options.annotations to dimension specific features instead of the bounding box; pass options.exploded { factor, mode } to explode the isometric cell, options.balloons to number parts from the BOM, and options.partsList for an item/name/qty/material table above the title block). overall bounding-box dimensions, title block; assemblies are drawn with inter-part occlusion; pass options.annotations to dimension specific features instead of the bounding box, options.autoAnnotate to derive datums A/B/C, grouped hole callouts with position tolerances, hole positions, overall size, radius and chamfer callouts, flatness and an ISO 2768 note from the geometry (the result carries drawing_report with placed / overlapped counts), and options.sections for real section views on any cutting plane). pdf-drawing (the same sheet — views, dashed hidden lines, dimensions, hole callouts, GD&T, sections, parts list — as a printable vector PDF on a standard sheet, one call: ISO a4|a3|a2|a1|a0 or ANSI ansi-a…ansi-e landscape, default a3, or sheet \"auto\" / \"auto-ansi\" for the smallest sheet that holds the views at 1:1; the drawing scale is picked to fit; projection \"third\" (default) or \"first\" arranges the views and draws the matching symbol; a full title block carries title, part name, material, scale, units, sheet size, date and revision, settable through options.title / partName / material / revision / date; autoAnnotate is on unless options.annotations is given). Robot descriptions: urdf (tree-topology robot description), srdf (motion-planning semantics layered over the URDF), sdf-gazebo (SDFormat 1.10 with native ball joints, closed loops, and solved per-link poses), usd-isaac (ASCII USD physics stage: PhysicsArticulationRootAPI root, one rigid body per link at its solved pose with mass / centre of mass / principal inertia, PhysicsFixedJoint/PhysicsRevoluteJoint/PhysicsPrismaticJoint per mate with token axis, two-sided joint frames and limits, UsdPreviewSurface materials from the part appearance, and joint drives only when declared in options.drives { <mate>: { stiffness, damping, maxForce?, targetPosition? } }; options.collisionApproximation is convexHull | convexDecomposition; planar/cylindrical/pin_slot/ball mates fail closed with export.usd.joint-unsupported). bom-csv / bom-json (bill of materials over assembly.model()/solvedModel(): one row per distinct part — grouped by geometry/catalog identity, not name — with real instance quantity, kind, material, density, mass, bbox, fabrication process (`process` + `processSource`), and catalog provenance for purchased parts; same numbers as inspect({ of: 'bom' })). order-pack (a zip: one single-body file per fabricated part — STEP always, plus STL for 3d-print and DXF for sheet-cut rows, per-part drawing PDFs where available — with bom.csv/bom.json, vendor paste handoff texts for purchased rows and a machine-readable manifest; options processes / items narrow which rows are packed; nothing is uploaded). bend-table (tube bender tables over tube() records: one <tube name>.csv per tube with the LRA bend table, XYZ points, cut length and last straight; output_path is a DIRECTORY and the written files are reported in table_files; a script with no tube() fails with export.bend-table.no-tubes, and a script whose tube gates report errors writes nothing). urdf and sdf-gazebo also write one meshes/<part>.stl per link, and usd-isaac one meshes/<part>.usda mesh layer per link, next to output_path (reported in mesh_files) — ship the whole directory to the consumer. STL exports run a watertight verify by default; failures return ok: false with export.mesh.not-watertight (open-edge count + up to 5 crack-cluster locations) but the file is still written so the broken mesh can be inspected. Optional { feature_id } selects which feature to export (default: last). Optional { options } carries per-format options bag (see the kernelcad-mcp skill for the per-format keys: dxf layers/tolerance/unit/section/layout, 3mf printUnit/embedSource/arrange/orient/slicer/printer/infill, glb axis/draco).\n- target:'part' — export solved-assembly parts as individual binary STL files in their modeled (world-frame) positions. Pass { file | code }, plus { part, output_path } for one part or { output_dir } for all parts (files land at <output_dir>/<part>.stl). A watertight verify runs on every exported mesh by default and fails the call with export.mesh.not-watertight; unknown part names fail with export.part.not-found listing the valid names.\nPass { no_verify: true } to skip the watertight gate. All params except `target` are forwarded verbatim; each target fails closed on its own missing required params.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "target": {
            "type": "string",
            "enum": [
              "model",
              "part"
            ],
            "description": "Which exporter to run: 'model' (whole-script geometry to one file) or 'part' (per-part STLs from a solved assembly)."
          },
          "file": {
            "type": "string",
            "description": "Path to a .kcad.ts script file."
          },
          "code": {
            "type": "string",
            "description": "Inline kernelCAD script source."
          },
          "output_path": {
            "type": "string",
            "description": "Destination path (a directory for format 'bend-table'). target:'model' — the export file (required). target:'part' — single-part .stl path."
          },
          "format": {
            "type": "string",
            "enum": [
              "stl",
              "step",
              "dxf",
              "3mf",
              "glb",
              "obj",
              "usd",
              "svg-drawing",
              "pdf-drawing",
              "urdf",
              "srdf",
              "sdf-gazebo",
              "usd-isaac",
              "bom-csv",
              "bom-json",
              "order-pack",
              "bend-table",
              "gcode"
            ],
            "description": "target:'model' — output file format (required for that target)."
          },
          "feature_id": {
            "type": "string",
            "description": "target:'model' — optional FeatureId to export; defaults to last."
          },
          "options": {
            "type": "object",
            "description": "target:'model' — optional per-format options bag. Discriminator options.format must equal top-level format. dxf: { layers?, unit?: \"mm\"|\"cm\"|\"in\", tolerance?, section?: { axis: \"x\"|\"y\"|\"z\", at: mm }, layout?: \"per-part\"|\"sheet\" }. 3mf: { printUnit?: \"mm\"|\"cm\"|\"in\", embedSource?, arrange?: \"none\"|\"plate\"|\"assembled\", orient?: boolean, slicer?: \"generic\"|\"bambu\"|\"orca\"|\"prusa\", printer?: printer profile id, one of \"generic-fdm\"|\"bambu-a1-mini\"|\"bambu-a1\"|\"bambu-p1s\"|\"bambu-p1p\"|\"bambu-x1c\"|\"bambu-x1e\"|\"bambu-h2d\"|\"bambu-h2s\"|\"prusa-mini-plus\"|\"prusa-mk4s\"|\"prusa-core-one\"|\"prusa-xl\"|\"creality-ender-3-v3\"|\"creality-k1\"|\"creality-k1-max\"|\"creality-k2-plus\"|\"elegoo-neptune-4-pro\"|\"anycubic-kobra-3\"|\"voron-2.4-250\"|\"voron-2.4-300\"|\"voron-2.4-350\"|\"ultimaker-s5\" (default \"generic-fdm\"; sets the bed for arrange and the slicer default; an unknown id is refused with the valid list; CLI: kernelcad print printers) }; parts that do not fit the bed are still written and reported as warn diagnostics export.3mf.plate-overflow / export.3mf.exceeds-bed, whose hint names the smallest profiles the layout fits on. gcode: { printer?: printer profile id, layerHeight?: mm, infill?: percent, supports?: boolean, material?: string }; requires a locally installed OrcaSlicer. Returns slicer predictions as gcode_stats; does not start a printer. glb: { axis?: \"y-up\"|\"z-up\", draco?: false }. obj and usd are mesh exports with no extra options; usd writes ASCII USDA (millimeter, Z-up). svg-drawing: { views?: [\"front\"], sheet?: \"a4\"|\"a3\" (or any pdf-drawing sheet), projection?, titleBlock?: { title?, partName?, material?, revision? }, modelName?, date?, annotations?, exploded?: { factor, mode? }, balloons?, partsList?, sections?, autoAnnotate? }. views:[\"front\"] produces a centred front-only elevation for SVG or PDF; omit views for four views. Front-only sheets require front annotations and reject isometric balloons/exploded overlays. svg-drawing annotations is an array of authored dimensions/notes, each { kind: \"linear\"|\"radius\"|\"diameter\"|\"angular\"|\"note\", view?: \"front\"|\"top\"|\"left\"|\"iso\", text?, offset? } plus kind-specific geometry: linear { from, to }, radius/diameter { edge: EdgeQuery }, angular { from: EdgeQuery, to: EdgeQuery }, note { at, text }. from/to/at anchors are an [x,y,z] model point, { edge: EdgeQuery } or { face: FaceQuery }. Supplying any annotation REPLACES the automatic bounding-box dimensions; an annotation whose query resolves to zero or multiple matches fails the export rather than being dropped. svg-drawing sections is an array of { plane: \"xy\"|\"xz\"|\"yz\"|{ origin, normal }, label } (any non-zero normal). svg-drawing autoAnnotate is true or { tolerance?: \"ISO2768-f\"|\"ISO2768-m\"|\"ISO2768-c\", datums?: \"auto\"|[{ label, face: FaceQuery }], include?: [\"datums\"|\"flatness\"|\"holes\"|\"hole-positions\"|\"overall\"|\"fillets\"|\"chamfers\"|\"general-tolerance\"], dimensioningStyle?: \"baseline\"|\"chain\"|\"symmetry\" }; datums and tolerances declared in the script with shape.datum() / shape.tolerance() override the automatic ones. pdf-drawing: { sheet?: \"a4\"|\"a3\"|\"a2\"|\"a1\"|\"a0\"|\"ansi-a\"|\"ansi-b\"|\"ansi-c\"|\"ansi-d\"|\"ansi-e\"|\"auto\"|\"auto-ansi\" (default \"a3\"), projection?: \"third\"|\"first\", title?, partName?, material?, revision?, date? (default today), modelName?, views?: [\"front\"], annotations?, sections?, exploded?, balloons?, partsList?, autoAnnotate? (default true unless annotations are given) } — the svg-drawing keys mean the same. Mechanical SVG/PDF also accept draftingProfile?: \"general\"|\"machining\"|\"sheet-metal\" or { id, name, sheet, projection, dimensioningStyle, tolerance?, notes? }, with explicit options overriding profile defaults. Functional drawing review: shape.drawingReview(plan) source declarations merge with reviewPlans?: additional plans; decisionResolutions?: { [encodeURIComponent(planId)+\":\"+encodeURIComponent(decisionId)]: { note, provenance } }. drawing_report.review reports declared geometric-callout coverage and unresolved engineering decisions. requireCompleteReview?: true rejects incomplete/not-declared mechanical reviews before export; architectural style rejects review contracts. Coverage is not engineering certification. annotationOverrides?: { [drawing_report.annotations[i].id]: { suppress?, text?, view?, offset? } }; offset is extra nonnegative sheet mm. Text edits primary labels while preserving attached FCFs; datum/standalone FCF text is changed in its declaration instead. Suppressed rows remain in the report but not visible counts. Missing IDs warn after geometry edits. Authored annotations can set id for stable review identity. svg-drawing and pdf-drawing also take style?: \"mechanical\" (default, the part sheet) | \"architectural\" (a floor plan for a building or room model: section about 1 m above the floor with filled cut walls, wall / opening chain dimensions and overall sizes, room labels with net area, scale bar, north arrow; millimetres, or feet-inches when the model is in whole feet / inches) and plan?: { units?: \"metric\"|\"imperial\", cutHeight?: mm above the floor, rooms?: [{ name, at: [x, y] }], northDeg?: degrees clockwise from sheet up }. A building-sized model drawn in the default style gets a drawing.style.architectural-suggested warning."
          },
          "part": {
            "type": "string",
            "description": "target:'part' — part name for single-part export, or 'all'."
          },
          "output_dir": {
            "type": "string",
            "description": "target:'part' — destination directory (all-parts mode); files are <dir>/<part>.stl."
          },
          "no_verify": {
            "type": "boolean",
            "description": "Skip the STL watertight verify gate.",
            "default": false
          }
        },
        "required": [
          "target"
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": true
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "sceneSummary": {
            "type": "object",
            "properties": {
              "valid": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "BREP validity, independent of DFM/mechanism/tool success; null if unchecked."
              },
              "volume": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Volume in mm³; assembly parts summed, including overlaps."
              },
              "faceCount": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "BREP faces, summed per assembly part; not mesh triangles."
              },
              "size": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3,
                "description": "Conservative world AABB size [x,y,z] in mm."
              }
            },
            "required": [
              "valid",
              "volume",
              "faceCount",
              "size"
            ],
            "additionalProperties": false
          },
          "ok": {
            "type": "boolean"
          },
          "output_path": {
            "type": "string",
            "description": "target:'model' — written file path."
          },
          "byte_count": {
            "type": "number",
            "description": "target:'model' — file size in bytes."
          },
          "feature_count": {
            "type": "number"
          },
          "format": {
            "type": "string"
          },
          "gcode_stats": {
            "type": "object",
            "description": "G-code only: slicer predictions and generator identity reported by artifact comments; not physical measurements.",
            "properties": {
              "slicer": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "enum": [
                      "OrcaSlicer",
                      "PrusaSlicer"
                    ]
                  },
                  "version": {
                    "type": "string"
                  }
                },
                "required": [
                  "name",
                  "version"
                ],
                "additionalProperties": false
              },
              "estimatedPrintTimeSeconds": {
                "type": "number",
                "minimum": 0
              },
              "filamentUsedGrams": {
                "type": "number",
                "minimum": 0
              },
              "filamentUsedMeters": {
                "type": "number",
                "minimum": 0
              },
              "layerCount": {
                "type": "integer",
                "minimum": 0
              },
              "maxZMm": {
                "type": "number",
                "minimum": 0
              }
            },
            "additionalProperties": false
          },
          "mesh_files": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Per-link mesh files: meshes/<part>.stl for urdf/sdf-gazebo, meshes/<part>.usda mesh layers for usd-isaac."
          },
          "part_files": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Per-part DXF files: parts/<part>.dxf for a multi-part dxf export (layout 'per-part', the default)."
          },
          "written": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "target:'part' — per-part export records."
          },
          "infill": {
            "type": "object",
            "additionalProperties": true,
            "description": "3mf with options.infill — stress-graded infill: band table (density, stress range, volume %), saving vs uniform infill at the high density, FEA peaks, and images { heatmap, bands, cutaway } PNG paths."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "error": {
            "type": "string"
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "lookup_cookbook",
      "description": "Use this when you need a canonical pattern snippet for a CAD task. Search the kernelCAD cookbook for canonical pattern snippets. Returns top-k snippets matching the natural-language query, ranked by BM25 over title/tags/keywords/trigger. Use when you need a canonical pattern for fillet-after-subtract, non-overlapping booleans, sketch-to-extrude flows, etc. Returns empty if no snippet scores above the relevance floor — proceed without cookbook help in that case.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string",
            "description": "Natural-language description of what you want to do (e.g. \"round the rim of a hole\", \"build an L-bracket\"). One of query / id is required."
          },
          "id": {
            "type": "string",
            "description": "Exact snippet id as the skills cite it (e.g. \"clearance-hole-through-plate\"); returns that snippet. An unknown id is ranked as a query."
          },
          "k": {
            "type": "number",
            "description": "Max snippets to return. Default 3, max 5.",
            "default": 3
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "hits": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Top-k matching cookbook snippets, ranked by BM25."
          },
          "error": {
            "type": "string"
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "find_part",
      "description": "Use this when you need to find a part in the catalog. Discover bundled (and optionally remote) part-catalog records by fuzzy query and faceted filters. Tokens AND-combine; cross-facet filters AND-combine. Pass partsBaseUrl (or set KERNELCAD_PARTS_BASE_URL) to enable the remote tier; otherwise results are bundled-only.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "family": {
            "type": "string"
          },
          "standard": {
            "type": "string"
          },
          "tag": {
            "type": "string"
          },
          "limit": {
            "type": "number"
          },
          "source": {
            "type": "string",
            "enum": [
              "local",
              "remote",
              "auto"
            ]
          },
          "partsBaseUrl": {
            "type": "string",
            "description": "Opt-in remote endpoint; no default value ships with kernelCAD."
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": true
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "results": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Matching part records (success)."
          },
          "totalMatches": {
            "type": "number",
            "description": "Total matches before limiting (success)."
          },
          "source": {
            "type": "string",
            "description": "Where results came from ('local' | 'remote') (success)."
          },
          "remoteEnabled": {
            "type": "boolean",
            "description": "Whether the remote tier was queried (success)."
          },
          "error": {
            "type": "string"
          },
          "errorCode": {
            "type": "string"
          },
          "errorHint": {
            "type": "string"
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "fetch_part",
      "description": "Use this when you need to download a catalog part as a STEP file. Resolve an id (or single-match query) to a part record and write its STEP file to the local cache. Bundled ids resolve offline; non-bundled ids require partsBaseUrl (or KERNELCAD_PARTS_BASE_URL). Returns the cache path plus a sha256 fingerprint. Set includeModel (or pass model.url) to instead resolve a verified STEP or GLB model file: a model.url must be public HTTPS with model.sha256 plus model.source and model.license; a catalog id/query (matched as catalog id or MPN) uses the catalog hash. The bytes are hash-checked and cached by SHA-256, optional model.expectedBboxMm is compared with the measured STEP/GLB dimensions (GLB only when POSITION bounds exist, else bbox_check.status is not_checked), and the result is { ok, format, model_path, sha256, cache_hit, bbox_check, attribution } or an errorCode such as model_not_found.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "query": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "family": {
            "type": "string"
          },
          "standard": {
            "type": "string"
          },
          "partsBaseUrl": {
            "type": "string",
            "description": "Opt-in remote endpoint; no default value ships with kernelCAD."
          },
          "includeModel": {
            "type": "boolean",
            "description": "Resolve a hash-verified STEP/GLB model file instead of the plain catalog STEP record."
          },
          "model": {
            "type": "object",
            "description": "Verified model options; supplying model implies includeModel.",
            "properties": {
              "url": {
                "type": "string",
                "description": "Direct public HTTPS .step/.stp/.glb download URL. Requires sha256, source and license."
              },
              "sha256": {
                "type": "string",
                "description": "Required SHA-256 digest for an explicit URL; for catalog parts it overrides the catalog GLB digest."
              },
              "source": {
                "type": "string",
                "description": "Catalog or manufacturer name, such as KiCad Packages3D."
              },
              "license": {
                "type": "string",
                "description": "License string supplied by the source."
              },
              "attribution": {
                "type": "string"
              },
              "expectedBboxMm": {
                "type": "array",
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3,
                "description": "Expected [x,y,z] dimensions to compare with the measured model."
              },
              "toleranceRatio": {
                "type": "number",
                "description": "Relative expected-versus-measured bbox tolerance, default 0.25."
              }
            }
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": true
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "record": {
            "type": "object",
            "additionalProperties": true,
            "description": "Resolved part record (success)."
          },
          "cachePath": {
            "type": "string",
            "description": "Local cache path of the written STEP file (success)."
          },
          "sha256": {
            "type": "string",
            "description": "SHA-256 fingerprint of the STEP file (success)."
          },
          "source": {
            "type": "string",
            "description": "Where the part came from ('local' | 'remote') (success)."
          },
          "kind": {
            "type": "string",
            "description": "'link_out' when the URL is a vendor configurator the agent must drive by hand."
          },
          "url": {
            "type": "string",
            "description": "Outbound vendor URL (link_out). May carry a referral tag; see disclosure."
          },
          "instruction": {
            "type": "string",
            "description": "What to do with the link_out URL."
          },
          "disclosure": {
            "type": "string",
            "description": "Referral disclosure. Present only when url carries a referral tag; show it with the link."
          },
          "format": {
            "type": "string",
            "enum": [
              "step",
              "glb"
            ],
            "description": "Model format (includeModel mode)."
          },
          "model_path": {
            "type": "string",
            "description": "Local cache path of the verified model file (includeModel mode)."
          },
          "cache_hit": {
            "type": "boolean",
            "description": "Whether the verified model came from the SHA-256 cache (includeModel mode)."
          },
          "bbox_check": {
            "type": "object",
            "properties": {
              "status": {
                "type": "string",
                "enum": [
                  "not_checked",
                  "within_tolerance",
                  "outside_tolerance"
                ]
              },
              "expected_mm": {
                "type": "array",
                "items": {
                  "type": "number"
                }
              },
              "actual_mm": {
                "type": "array",
                "items": {
                  "type": "number"
                }
              },
              "tolerance_ratio": {
                "type": "number"
              }
            },
            "additionalProperties": true
          },
          "attribution": {
            "type": "object",
            "additionalProperties": true,
            "description": "Model provenance { source, license, url?, attribution? } (includeModel mode)."
          },
          "error": {
            "type": "string"
          },
          "errorCode": {
            "type": "string"
          },
          "errorHint": {
            "type": "string"
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "solve_sketch",
      "description": "Use this when you need to solve a 2D sketch constraint set. Solve a 2D sketch constraint set. Side-effect-free: pass { entities, constraints } and receive solved entities plus the original constraints. Entities are POINT, LINE, and CIRCLE records; constraints use the kernelCAD constraint vocabulary.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "entities": {
            "type": "array",
            "description": "Sketch entities to solve. Lines reference point ids; circles reference a center point id.",
            "items": {
              "oneOf": [
                {
                  "type": "object",
                  "description": "POINT — a 2D point.",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "type": {
                      "type": "string",
                      "enum": [
                        "POINT"
                      ]
                    },
                    "x": {
                      "type": "number"
                    },
                    "y": {
                      "type": "number"
                    },
                    "fixed": {
                      "type": "boolean",
                      "description": "If true, the solver won't move this point."
                    }
                  },
                  "required": [
                    "id",
                    "type",
                    "x",
                    "y"
                  ]
                },
                {
                  "type": "object",
                  "description": "LINE — references two point ids.",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "type": {
                      "type": "string",
                      "enum": [
                        "LINE"
                      ]
                    },
                    "p1": {
                      "type": "string"
                    },
                    "p2": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "id",
                    "type",
                    "p1",
                    "p2"
                  ]
                },
                {
                  "type": "object",
                  "description": "CIRCLE — references a center point id.",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "type": {
                      "type": "string",
                      "enum": [
                        "CIRCLE"
                      ]
                    },
                    "center": {
                      "type": "string"
                    },
                    "radius": {
                      "type": "number"
                    }
                  },
                  "required": [
                    "id",
                    "type",
                    "center",
                    "radius"
                  ]
                }
              ]
            }
          },
          "constraints": {
            "type": "array",
            "description": "Constraints to apply to the entities.",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "type": {
                  "type": "string",
                  "enum": [
                    "COINCIDENT",
                    "DISTANCE",
                    "HORIZONTAL",
                    "VERTICAL",
                    "PARALLEL",
                    "PERPENDICULAR",
                    "EQUAL_LENGTH",
                    "TANGENT",
                    "RADIUS",
                    "ANGLE",
                    "CONCENTRIC",
                    "SYMMETRIC"
                  ]
                },
                "entities": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  },
                  "description": "Ids of the entities the constraint relates."
                },
                "value": {
                  "type": "number",
                  "description": "Required for DISTANCE, RADIUS, and ANGLE."
                }
              },
              "required": [
                "id",
                "type",
                "entities"
              ]
            }
          }
        },
        "required": [
          "entities",
          "constraints"
        ]
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "converged": {
            "type": "boolean",
            "description": "Whether the constraint solve converged below tolerance. ok is false when this is false."
          },
          "residual": {
            "type": "number",
            "description": "Final aggregate constraint residual when the solver ran."
          },
          "entities": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Solved sketch entities (best-effort on a non-converging solve)."
          },
          "constraints": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "The constraints applied."
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Solver/validation errors (present on failure, including non-convergence)."
          }
        },
        "required": [
          "ok",
          "entities",
          "constraints"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "add_constraint",
      "description": "Use this when you need to add a sketch constraint to a list. Append one validated sketch constraint to a constraint list. Side-effect-free: pass { constraints, constraint } and receive the updated list.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "constraints": {
            "type": "array",
            "description": "Existing constraint list to append to (omit for an empty list).",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "type": {
                  "type": "string",
                  "enum": [
                    "COINCIDENT",
                    "DISTANCE",
                    "HORIZONTAL",
                    "VERTICAL",
                    "PARALLEL",
                    "PERPENDICULAR",
                    "EQUAL_LENGTH",
                    "TANGENT",
                    "RADIUS",
                    "ANGLE",
                    "CONCENTRIC",
                    "SYMMETRIC"
                  ]
                },
                "entities": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "value": {
                  "type": "number"
                }
              },
              "required": [
                "id",
                "type",
                "entities"
              ]
            }
          },
          "constraint": {
            "type": "object",
            "description": "The constraint to append.",
            "properties": {
              "id": {
                "type": "string"
              },
              "type": {
                "type": "string",
                "enum": [
                  "COINCIDENT",
                  "DISTANCE",
                  "HORIZONTAL",
                  "VERTICAL",
                  "PARALLEL",
                  "PERPENDICULAR",
                  "EQUAL_LENGTH",
                  "TANGENT",
                  "RADIUS",
                  "ANGLE",
                  "CONCENTRIC",
                  "SYMMETRIC"
                ]
              },
              "entities": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Ids of the entities the constraint relates."
              },
              "value": {
                "type": "number",
                "description": "Required for DISTANCE, RADIUS, and ANGLE."
              }
            },
            "required": [
              "id",
              "type",
              "entities"
            ]
          }
        },
        "required": [
          "constraint"
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "constraints": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Updated constraint list."
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Validation errors (present on failure)."
          }
        },
        "required": [
          "ok",
          "constraints"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "add_part",
      "description": "Use this when you need to add a part to an assembly. Durably insert `const <binding> = <assembly>.part(partName, shapeExpression, opts?)` before the final top-level return in a kernelCAD source string. Returns modified source plus diagnostics from re-evaluating it. Side-effect-free: caller persists the returned source.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The .kcad.ts source code."
          },
          "assembly_binding": {
            "type": "string",
            "description": "JS identifier bound to assembly(...), e.g. \"arm\"."
          },
          "part_name": {
            "type": "string",
            "description": "Assembly-unique part name."
          },
          "shape_expression": {
            "type": "string",
            "description": "JS expression for the Shape to pass to assembly.part, inserted verbatim."
          },
          "binding_name": {
            "type": "string",
            "description": "Optional JS const name for the returned AssemblyPartRef. Defaults to a part-name-derived identifier."
          },
          "at": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "description": "Optional [x, y, z] assembly placement."
          }
        },
        "required": [
          "code",
          "assembly_binding",
          "part_name",
          "shape_expression"
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "description": "Whether the edit applied and re-evaluated cleanly."
          },
          "viewerUrl": {
            "type": "string",
            "description": "Same live Studio link when this edit built a replacement model."
          },
          "viewerError": {
            "type": "string",
            "description": "Viewer provisioning error, independent of edit diagnostics."
          },
          "viewerMode": {
            "type": "string",
            "enum": [
              "hosted"
            ],
            "description": "Hosted mode uses open_in_studio instead of a process-local viewer."
          },
          "viewerHint": {
            "type": "string",
            "description": "How to view the built model in hosted Studio."
          },
          "step": {
            "type": "object",
            "additionalProperties": true,
            "description": "Per-step build validity, volume and paired local PNG paths with a shared iso frame; unavailable snapshots report an error. Not a topology certificate. Omitted on dry runs."
          },
          "sceneSummary": {
            "type": "object",
            "properties": {
              "valid": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "BREP validity, independent of DFM/mechanism/tool success; null if unchecked."
              },
              "volume": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Volume in mm³; assembly parts summed, including overlaps."
              },
              "faceCount": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "BREP faces, summed per assembly part; not mesh triangles."
              },
              "size": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3,
                "description": "Conservative world AABB size [x,y,z] in mm."
              }
            },
            "required": [
              "valid",
              "volume",
              "faceCount",
              "size"
            ],
            "additionalProperties": false
          },
          "new_code": {
            "type": "string",
            "description": "Modified .kcad.ts source (present on success). Caller persists it."
          },
          "binding_name": {
            "type": "string",
            "description": "JS const name bound to the new construct (when one was created)."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Diagnostics from re-evaluating the modified source."
          },
          "error": {
            "type": "string",
            "description": "Failure message (present when ok is false)."
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "add_connector",
      "description": "Use this when you need to add a mate connector to a part. Durably insert `<partBinding>.connector(name, { type, origin, axis?, normal? })` before the final top-level return. Use the part binding returned by add_part. Returns modified source plus diagnostics from re-evaluation. Side-effect-free.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The .kcad.ts source code."
          },
          "part_binding": {
            "type": "string",
            "description": "JS identifier bound to an AssemblyPartRef, e.g. \"basePart\"."
          },
          "name": {
            "type": "string",
            "description": "Connector name unique within the part."
          },
          "type": {
            "type": "string",
            "enum": [
              "frame",
              "axis",
              "planar",
              "ball"
            ]
          },
          "origin": {
            "description": "Origin as [x, y, z] shorthand, or a structured ConnectorOrigin.",
            "oneOf": [
              {
                "type": "array",
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3,
                "description": "[x, y, z] shorthand."
              },
              {
                "type": "object",
                "description": "Explicit numeric origin.",
                "properties": {
                  "kind": {
                    "type": "string",
                    "enum": [
                      "vec3"
                    ]
                  },
                  "value": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    },
                    "minItems": 3,
                    "maxItems": 3
                  }
                },
                "required": [
                  "kind",
                  "value"
                ]
              },
              {
                "type": "object",
                "description": "Topology-derived origin.",
                "properties": {
                  "kind": {
                    "type": "string",
                    "enum": [
                      "topology"
                    ]
                  },
                  "query": {
                    "type": "object",
                    "properties": {
                      "kind": {
                        "type": "string",
                        "enum": [
                          "face-center",
                          "face-normal",
                          "vertex",
                          "edge-axis"
                        ]
                      },
                      "name": {
                        "type": "string"
                      }
                    },
                    "required": [
                      "kind",
                      "name"
                    ]
                  }
                },
                "required": [
                  "kind",
                  "query"
                ]
              }
            ]
          },
          "axis": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "description": "Optional [x, y, z] axis."
          },
          "normal": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "description": "Optional [x, y, z] normal."
          }
        },
        "required": [
          "code",
          "part_binding",
          "name",
          "type",
          "origin"
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "description": "Whether the edit applied and re-evaluated cleanly."
          },
          "viewerUrl": {
            "type": "string",
            "description": "Same live Studio link when this edit built a replacement model."
          },
          "viewerError": {
            "type": "string",
            "description": "Viewer provisioning error, independent of edit diagnostics."
          },
          "viewerMode": {
            "type": "string",
            "enum": [
              "hosted"
            ],
            "description": "Hosted mode uses open_in_studio instead of a process-local viewer."
          },
          "viewerHint": {
            "type": "string",
            "description": "How to view the built model in hosted Studio."
          },
          "step": {
            "type": "object",
            "additionalProperties": true,
            "description": "Per-step build validity, volume and paired local PNG paths with a shared iso frame; unavailable snapshots report an error. Not a topology certificate. Omitted on dry runs."
          },
          "sceneSummary": {
            "type": "object",
            "properties": {
              "valid": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "BREP validity, independent of DFM/mechanism/tool success; null if unchecked."
              },
              "volume": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Volume in mm³; assembly parts summed, including overlaps."
              },
              "faceCount": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "BREP faces, summed per assembly part; not mesh triangles."
              },
              "size": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3,
                "description": "Conservative world AABB size [x,y,z] in mm."
              }
            },
            "required": [
              "valid",
              "volume",
              "faceCount",
              "size"
            ],
            "additionalProperties": false
          },
          "new_code": {
            "type": "string",
            "description": "Modified .kcad.ts source (present on success). Caller persists it."
          },
          "binding_name": {
            "type": "string",
            "description": "JS const name bound to the new construct (when one was created)."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Diagnostics from re-evaluating the modified source."
          },
          "error": {
            "type": "string",
            "description": "Failure message (present when ok is false)."
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "add_mate",
      "description": "Use this when you need to author a mate-graph relationship into the source, selected by `relation` (default 'mate'):\n- 'mate' — a typed mate between two connectors ({ name, a, b, type, pose?, limitsDeg?, limitsMm? }).\n- 'coupling' — couple a driven mate to a source mate by ratio ({ driven, source, ratio, offset? }).\n- 'transmission' — a physical drive path across mates ({ name, kind, sourceMate, drivenMates, path, ... }).\nAll durably edit source and need { code, assembly_binding }. Params other than `relation` are forwarded verbatim; each relation fails closed on its own missing required params.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "relation": {
            "type": "string",
            "enum": [
              "mate",
              "coupling",
              "transmission"
            ],
            "description": "Which relationship to author (default 'mate')."
          },
          "code": {
            "type": "string",
            "description": "The .kcad.ts source code."
          },
          "assembly_binding": {
            "type": "string",
            "description": "JS identifier bound to assembly(...)."
          },
          "name": {
            "type": "string",
            "description": "relation:'mate'|'transmission' — name unique within the assembly."
          },
          "a": {
            "type": "string",
            "description": "relation:'mate' — connector ref \"<partName>.<connectorName>\"."
          },
          "b": {
            "type": "string",
            "description": "relation:'mate' — connector ref \"<partName>.<connectorName>\"."
          },
          "type": {
            "type": "string",
            "enum": [
              "fastened",
              "revolute",
              "prismatic",
              "cylindrical",
              "planar",
              "ball",
              "pin_slot"
            ],
            "description": "relation:'mate' — mate type."
          },
          "pose": {
            "type": "object",
            "description": "relation:'mate' — optional mate pose."
          },
          "limitsDeg": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "description": "relation:'mate' — optional [minDeg, maxDeg]."
          },
          "limitsMm": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "description": "relation:'mate' — optional [minMm, maxMm]."
          },
          "driven": {
            "type": "string",
            "description": "relation:'coupling' — driven mate name."
          },
          "source": {
            "type": "string",
            "description": "relation:'coupling' — source mate name."
          },
          "ratio": {
            "type": "number",
            "description": "relation:'coupling' — driven pose = source pose * ratio + offset."
          },
          "offset": {
            "type": "number",
            "description": "relation:'coupling' — optional pose offset."
          },
          "kind": {
            "type": "string",
            "enum": [
              "direct",
              "link-rod",
              "four-bar",
              "gear-pair",
              "belt",
              "tendon"
            ],
            "description": "relation:'transmission' — transmission kind."
          },
          "sourceMate": {
            "type": "string",
            "description": "relation:'transmission' — source mate name."
          },
          "drivenMates": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "relation:'transmission' — driven mate names."
          },
          "actuator": {
            "type": "string",
            "description": "relation:'transmission' — optional actuator."
          },
          "input": {
            "type": "string",
            "description": "relation:'transmission' — optional input."
          },
          "output": {
            "type": "string",
            "description": "relation:'transmission' — optional output."
          },
          "path": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "relation:'transmission' — drive path."
          },
          "notes": {
            "type": "string",
            "description": "relation:'transmission' — optional notes."
          }
        },
        "required": [
          "code",
          "assembly_binding"
        ],
        "allOf": [
          {
            "if": {
              "properties": {
                "relation": {
                  "const": "coupling"
                }
              },
              "required": [
                "relation"
              ]
            },
            "then": {
              "required": [
                "driven",
                "source",
                "ratio"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "relation": {
                  "const": "transmission"
                }
              },
              "required": [
                "relation"
              ]
            },
            "then": {
              "required": [
                "name",
                "kind",
                "sourceMate",
                "drivenMates",
                "path"
              ]
            }
          },
          {
            "if": {
              "properties": {
                "relation": {
                  "enum": [
                    "coupling",
                    "transmission"
                  ]
                }
              },
              "required": [
                "relation"
              ]
            },
            "then": {},
            "else": {
              "required": [
                "name",
                "a",
                "b",
                "type"
              ]
            }
          }
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "description": "Whether the edit applied and re-evaluated cleanly."
          },
          "viewerUrl": {
            "type": "string",
            "description": "Same live Studio link when this edit built a replacement model."
          },
          "viewerError": {
            "type": "string",
            "description": "Viewer provisioning error, independent of edit diagnostics."
          },
          "viewerMode": {
            "type": "string",
            "enum": [
              "hosted"
            ],
            "description": "Hosted mode uses open_in_studio instead of a process-local viewer."
          },
          "viewerHint": {
            "type": "string",
            "description": "How to view the built model in hosted Studio."
          },
          "step": {
            "type": "object",
            "additionalProperties": true,
            "description": "Per-step build validity, volume and paired local PNG paths with a shared iso frame; unavailable snapshots report an error. Not a topology certificate. Omitted on dry runs."
          },
          "sceneSummary": {
            "type": "object",
            "properties": {
              "valid": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "BREP validity, independent of DFM/mechanism/tool success; null if unchecked."
              },
              "volume": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Volume in mm³; assembly parts summed, including overlaps."
              },
              "faceCount": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "BREP faces, summed per assembly part; not mesh triangles."
              },
              "size": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3,
                "description": "Conservative world AABB size [x,y,z] in mm."
              }
            },
            "required": [
              "valid",
              "volume",
              "faceCount",
              "size"
            ],
            "additionalProperties": false
          },
          "new_code": {
            "type": "string",
            "description": "Modified .kcad.ts source (present on success). Caller persists it."
          },
          "binding_name": {
            "type": "string",
            "description": "JS const name bound to the new construct (when one was created)."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Diagnostics from re-evaluating the modified source."
          },
          "error": {
            "type": "string",
            "description": "Failure message (present when ok is false)."
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "add_workspace_target",
      "description": "Use this when you need to declare a reachability target for a connector. Durably insert `<assembly>.workspace(connectorRef, { reachable, toleranceMm? })` before the final top-level return. Workspace targets are checked by solvedModel validation/review pose-envelope gates. Returns modified source plus diagnostics from re-evaluation.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The .kcad.ts source code."
          },
          "assembly_binding": {
            "type": "string",
            "description": "JS identifier bound to assembly(...)."
          },
          "connector_ref": {
            "type": "string",
            "description": "Connector ref \"<partName>.<connectorName>\"."
          },
          "reachable": {
            "type": "array",
            "description": "World-frame Vec3 targets the connector must be able to reach.",
            "items": {
              "type": "array",
              "items": {
                "type": "number"
              },
              "minItems": 3,
              "maxItems": 3
            }
          },
          "toleranceMm": {
            "type": "number",
            "description": "Optional non-negative tolerance in mm."
          }
        },
        "required": [
          "code",
          "assembly_binding",
          "connector_ref",
          "reachable"
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "description": "Whether the edit applied and re-evaluated cleanly."
          },
          "viewerUrl": {
            "type": "string",
            "description": "Same live Studio link when this edit built a replacement model."
          },
          "viewerError": {
            "type": "string",
            "description": "Viewer provisioning error, independent of edit diagnostics."
          },
          "viewerMode": {
            "type": "string",
            "enum": [
              "hosted"
            ],
            "description": "Hosted mode uses open_in_studio instead of a process-local viewer."
          },
          "viewerHint": {
            "type": "string",
            "description": "How to view the built model in hosted Studio."
          },
          "step": {
            "type": "object",
            "additionalProperties": true,
            "description": "Per-step build validity, volume and paired local PNG paths with a shared iso frame; unavailable snapshots report an error. Not a topology certificate. Omitted on dry runs."
          },
          "sceneSummary": {
            "type": "object",
            "properties": {
              "valid": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "BREP validity, independent of DFM/mechanism/tool success; null if unchecked."
              },
              "volume": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Volume in mm³; assembly parts summed, including overlaps."
              },
              "faceCount": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "BREP faces, summed per assembly part; not mesh triangles."
              },
              "size": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3,
                "description": "Conservative world AABB size [x,y,z] in mm."
              }
            },
            "required": [
              "valid",
              "volume",
              "faceCount",
              "size"
            ],
            "additionalProperties": false
          },
          "new_code": {
            "type": "string",
            "description": "Modified .kcad.ts source (present on success). Caller persists it."
          },
          "binding_name": {
            "type": "string",
            "description": "JS const name bound to the new construct (when one was created)."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Diagnostics from re-evaluating the modified source."
          },
          "error": {
            "type": "string",
            "description": "Failure message (present when ok is false)."
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "set_scene_return",
      "description": "Use this when you need to set how the script returns its assembly. Replace the final top-level return statement with `return <assembly>.model();` or `return <assembly>.solvedModel(poses, options?);`. Use solvedModel for mate-authored mechanisms so FK and validation run. Returns modified source plus diagnostics from re-evaluation.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The .kcad.ts source code."
          },
          "assembly_binding": {
            "type": "string",
            "description": "JS identifier bound to assembly(...)."
          },
          "mode": {
            "type": "string",
            "enum": [
              "model",
              "solvedModel"
            ]
          },
          "poses": {
            "type": "object",
            "description": "Optional solvedModel pose overrides keyed by mate name. Defaults to {}."
          },
          "options": {
            "type": "object",
            "description": "Optional solvedModel options such as { validate: 'warn', posesGate: 'envelope' }."
          }
        },
        "required": [
          "code",
          "assembly_binding",
          "mode"
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "description": "Whether the edit applied and re-evaluated cleanly."
          },
          "viewerUrl": {
            "type": "string",
            "description": "Same live Studio link when this edit built a replacement model."
          },
          "viewerError": {
            "type": "string",
            "description": "Viewer provisioning error, independent of edit diagnostics."
          },
          "viewerMode": {
            "type": "string",
            "enum": [
              "hosted"
            ],
            "description": "Hosted mode uses open_in_studio instead of a process-local viewer."
          },
          "viewerHint": {
            "type": "string",
            "description": "How to view the built model in hosted Studio."
          },
          "step": {
            "type": "object",
            "additionalProperties": true,
            "description": "Per-step build validity, volume and paired local PNG paths with a shared iso frame; unavailable snapshots report an error. Not a topology certificate. Omitted on dry runs."
          },
          "sceneSummary": {
            "type": "object",
            "properties": {
              "valid": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "BREP validity, independent of DFM/mechanism/tool success; null if unchecked."
              },
              "volume": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Volume in mm³; assembly parts summed, including overlaps."
              },
              "faceCount": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "BREP faces, summed per assembly part; not mesh triangles."
              },
              "size": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3,
                "description": "Conservative world AABB size [x,y,z] in mm."
              }
            },
            "required": [
              "valid",
              "volume",
              "faceCount",
              "size"
            ],
            "additionalProperties": false
          },
          "new_code": {
            "type": "string",
            "description": "Modified .kcad.ts source (present on success). Caller persists it."
          },
          "binding_name": {
            "type": "string",
            "description": "JS const name bound to the new construct (when one was created)."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Diagnostics from re-evaluating the modified source."
          },
          "error": {
            "type": "string",
            "description": "Failure message (present when ok is false)."
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "solve_mates",
      "description": "Use this when you need to solve the mate graph and get part poses. Run the v0.6 mate-graph solver on the active assembly. Returns { status, poses, iterations? } where each pose is a serialized Transform ({ translation, rotateAxis, rotateDeg }). Optional poses overrides mate pose values by mate name.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "assembly": {
            "type": "string"
          },
          "poses": {
            "type": "object",
            "description": "Optional numeric pose overrides keyed by mate name."
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "status": {
            "type": "string",
            "description": "Solver status (success)."
          },
          "poses": {
            "type": "object",
            "additionalProperties": true,
            "description": "Solved part poses keyed by mate; each a serialized Transform (success)."
          },
          "iterations": {
            "type": "number",
            "description": "Solver iteration count (success)."
          },
          "error": {
            "type": "string"
          },
          "errorCode": {
            "type": "string"
          },
          "errorHint": {
            "type": "string"
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "review_cad",
      "description": "Run a deterministic mechanism-fitness review on supplied kernelCAD code or a file. It performs a full evaluation, replaces the active MCP session model on success, and clears that session if evaluation fails. The script may load referenced assets. The review validates the assembly/mate graph and connector placement, samples declared mate limits, optionally checks interference at sampled poses, and reports connector workspace bounds, fitness findings, and a repair mode (none, local-fix, parameter-tune, or topology-redesign). Runs within timeBudgetMs (default 90 s); stages that do not fit are listed in skippedStages and were not checked.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "file": {
            "type": "string",
            "description": "Path to a .kcad.ts script file."
          },
          "code": {
            "type": "string",
            "description": "Inline kernelCAD script source."
          },
          "assembly": {
            "type": "string",
            "description": "Assembly name; defaults to the first captured assembly."
          },
          "designGoal": {
            "type": "string",
            "description": "Original user design prompt or goal. Included in suggestedRepairPrompt so topology-redesign repairs restart from the intended physical design instead of local coordinate nudges."
          },
          "preserveInterfaces": {
            "type": "array",
            "description": "External mates, connector refs, part names, or behavioral interfaces the repair agent must preserve during redesign.",
            "items": {
              "type": "string"
            }
          },
          "includePoseEnvelope": {
            "type": "boolean",
            "description": "Whether to sample declared mate limits. Default true."
          },
          "includeInterference": {
            "type": "boolean",
            "description": "Whether sampled poses run BREP interference checks. Default true."
          },
          "requirePhysicalUseCase": {
            "type": "boolean",
            "description": "When true, articulated assemblies must declare arm.physicalUseCase(...) evidence: loads, contacts, stable parts, and actuator limits."
          },
          "physicalUseCaseLevel": {
            "type": "string",
            "enum": [
              "reachability",
              "statics",
              "reactions"
            ],
            "description": "Escalating physical-use-case depth; each level includes the previous. 'reachability': targeted sampling over scalar-limited mates named in actuatorLimits, rejecting contacts that cannot get within criteria.maxSlipMm and multi-contact use cases that cannot satisfy every contact in the same sampled actuator pose (revolute/cylindrical/pin-slot limitsDeg, prismatic limitsMm). 'statics': adds pose-bound quasi-static certification at the exact common-contact samples (conservative friction/capacity, world force and moment balance, finite-difference revolute actuator torque); returns physicalUseCaseStaticCertificates on success. 'reactions': adds exact-pose reaction wrenches through uniquely rooted articulated trees, compared against each loaded mate's declared resultant force/moment envelope, and runs the clevis double-shear / pin-bending / bearing / tear-out / net-section check (minimum factor of safety 2) automatically for mates built with joint.clevis. Defaults to 'reachability' when requirePhysicalUseCase is true."
          },
          "physicalUseCaseSamplesPerMate": {
            "type": "integer",
            "minimum": 1,
            "description": "Samples per scalar-limited actuator mate for physical-use-case contact reachability. Samples revolute/cylindrical/pin-slot limitsDeg and prismatic limitsMm. Default 3; total targeted combinations are capped."
          },
          "samplesPerMate": {
            "type": "integer",
            "minimum": 1,
            "description": "Pose-envelope samples per declared-limit mate. 1 (default) = corners only; >=3 adds uniform interior points between min and max. Total samples per non-locked mate = samplesPerMate."
          },
          "combinatorial": {
            "type": "boolean",
            "description": "Sample all 2^N limit-corner combinations across mates with declared limits. Capped at 8 mates with limits; combine with samplesPerMate for both interior coverage and worst-pose detection. Default false."
          },
          "epsilonMm3": {
            "type": "number",
            "description": "Interference volume threshold in mm^3. Default 0.01."
          },
          "timeBudgetMs": {
            "type": "number",
            "description": "Wall-clock budget for the review in ms (default 90000). Once spent, the remaining heavy stages (pose envelope, physical use case, mechanism sweep) are skipped and listed in skippedStages — a partial result instead of a timeout. stageTimingsMs reports where the time went."
          },
          "trackConnectors": {
            "type": "array",
            "description": "Optional connector refs such as [\"gripper-plate.tool-tip\"] to limit connector workspace reporting.",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": true
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "stageTimingsMs": {
            "type": "object",
            "additionalProperties": {
              "type": "number"
            },
            "description": "Wall-clock ms per review stage that ran."
          },
          "skippedStages": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "stage": {
                  "type": "string"
                },
                "reason": {
                  "type": "string"
                }
              },
              "additionalProperties": true
            },
            "description": "Stages skipped because timeBudgetMs was spent; their checks did not run."
          },
          "featureCount": {
            "type": "number"
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "assembly": {
            "type": "string"
          },
          "validator": {
            "type": "object",
            "additionalProperties": true,
            "description": "Assembly/mate-graph validator result."
          },
          "poseEnvelope": {
            "type": "object",
            "additionalProperties": true,
            "description": "Sampled mate-limit pose envelope."
          },
          "connectorWorkspace": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Connector workspace bounds."
          },
          "physicalUseCaseStaticCertificates": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Verified sampled quasi-static certificates with residual wrench, contact forces, and actuator torque evidence."
          },
          "physicalUseCaseJointReactionCertificates": {
            "type": "array",
            "description": "Exact-pose parent-on-child joint reaction wrench certificates in N, mm, and Nmm.",
            "items": {
              "type": "object",
              "properties": {
                "useCaseName": {
                  "type": "string"
                },
                "poses": {
                  "type": "object",
                  "additionalProperties": true
                },
                "reactions": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "mateName": {
                        "type": "string"
                      },
                      "parentPart": {
                        "type": "string"
                      },
                      "childPart": {
                        "type": "string"
                      },
                      "pointWorldMm": {
                        "type": "array",
                        "items": {
                          "type": "number"
                        }
                      },
                      "axisWorld": {
                        "type": "array",
                        "items": {
                          "type": "number"
                        }
                      },
                      "forceWorldN": {
                        "type": "array",
                        "items": {
                          "type": "number"
                        }
                      },
                      "momentWorldNmm": {
                        "type": "array",
                        "items": {
                          "type": "number"
                        }
                      },
                      "resultantForceN": {
                        "type": "number"
                      },
                      "resultantMomentNmm": {
                        "type": "number"
                      },
                      "axialForceN": {
                        "type": "number"
                      },
                      "radialForceN": {
                        "type": "number"
                      },
                      "axisMomentNmm": {
                        "type": "number"
                      },
                      "bendingMomentNmm": {
                        "type": "number"
                      }
                    },
                    "required": [
                      "mateName",
                      "parentPart",
                      "childPart",
                      "pointWorldMm",
                      "axisWorld",
                      "forceWorldN",
                      "momentWorldNmm",
                      "resultantForceN",
                      "resultantMomentNmm",
                      "axialForceN",
                      "radialForceN",
                      "axisMomentNmm",
                      "bendingMomentNmm"
                    ],
                    "additionalProperties": false
                  }
                }
              },
              "required": [
                "useCaseName",
                "poses",
                "reactions"
              ],
              "additionalProperties": false
            }
          },
          "physicalUseCaseJointStructuralCertificates": {
            "type": "array",
            "description": "Per-joint declared-envelope and geometry/material clevis strength evidence.",
            "items": {
              "type": "object",
              "properties": {
                "useCaseName": {
                  "type": "string"
                },
                "poses": {
                  "type": "object",
                  "additionalProperties": true
                },
                "joints": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "mateName": {
                        "type": "string"
                      },
                      "envelope": {
                        "type": "object",
                        "additionalProperties": true
                      },
                      "structure": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    },
                    "required": [
                      "mateName",
                      "envelope"
                    ],
                    "additionalProperties": false
                  }
                }
              },
              "required": [
                "useCaseName",
                "poses",
                "joints"
              ],
              "additionalProperties": false
            }
          },
          "fitness": {
            "type": "object",
            "additionalProperties": true,
            "description": "Mechanism fitness verdict incl. repairMode."
          },
          "repairContext": {
            "type": "object",
            "additionalProperties": true
          },
          "rawInterferencePairs": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "interferenceSummary": {
            "type": "object",
            "additionalProperties": true,
            "description": "Classified interference counts and pairs: raw, contact-noise, actionable, and capMm3."
          },
          "mechanism": {
            "type": "string"
          },
          "mechanismFailures": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "mechanismSummary": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "verdict",
              "maxLevel",
              "statement",
              "checked",
              "skipped",
              "failures"
            ],
            "description": "Plain verdict for a model with moving joints or motion intent (animation, drive, transmission); absent for a static model. Read `statement`: 'Motion checked' names what ran, 'Motion not checked' names what was skipped (NOT a pass), 'Mechanism broken' names the joint.",
            "properties": {
              "verdict": {
                "type": "string",
                "enum": [
                  "real",
                  "broken",
                  "unverified"
                ]
              },
              "maxLevel": {
                "type": "string",
                "enum": [
                  "ok",
                  "warning",
                  "error"
                ],
                "description": "One status level: 'error' when broken, 'warning' when not checked, 'ok' when checked."
              },
              "statement": {
                "type": "string",
                "description": "One line. Quote it instead of calling the mechanism working."
              },
              "checked": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "What ran and held (verdict 'real')."
              },
              "skipped": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "What did not run and why. On 'real', the moving joint DOFs with no limits (range not checked)."
              },
              "failures": {
                "type": "array",
                "description": "Error failures (verdict 'broken'); `joint` names the mate and `part` the part when known.",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "code",
                    "reason"
                  ],
                  "properties": {
                    "code": {
                      "type": "string"
                    },
                    "reason": {
                      "type": "string"
                    },
                    "joint": {
                      "type": "string"
                    },
                    "part": {
                      "type": "string"
                    }
                  }
                }
              },
              "loads": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "maxLevel",
                  "statement"
                ],
                "description": "Motion-load line, present when a mechanicalJoint declares torqueNm. Full table: verify({ check: 'motion-load' }).",
                "properties": {
                  "maxLevel": {
                    "type": "string",
                    "enum": [
                      "ok",
                      "warning",
                      "error"
                    ]
                  },
                  "statement": {
                    "type": "string"
                  },
                  "joints": {
                    "type": "array",
                    "description": "Compact per-joint loads for the Studio Loads panel: peaks, support radial loads, and [tMs, torqueNm] pairs.",
                    "items": {
                      "type": "object",
                      "additionalProperties": true,
                      "required": [
                        "joint",
                        "peakTorqueNm"
                      ]
                    }
                  }
                }
              }
            }
          },
          "suggestedRepairPrompt": {
            "type": "string",
            "description": "Structured repair prompt (failure / repair path)."
          }
        },
        "required": [
          "ok",
          "featureCount",
          "diagnostics"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "design_loop",
      "description": "Use this when the goal is complex / production / enclosure / gearbox / robot-arm / multi-body, or when you need evaluate→review/verify→revise until green. PREFERRED over one-shot evaluate_script+open_in_studio for Adam-level parts. Runs a CAD design loop over attempt scripts: review_cad each attempt, continue past functional attempts with unresolved warnings, return repair prompts (nextActionPrompt) plus structured revisionAssist (suggestedPatches / autoApplied.suggestedCode for repairable feature failures; cookbook steers for stacked-primitive toys). Stop on ok or convergence.escalate. To pick among N alternative candidates for one goal without a judge, pass them all as attempts with consensus:true (geometric medoid selection). Optionally write a Studio build record JSON.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "goal": {
            "type": "string",
            "description": "Original user design goal. Fed into every review_cad repair prompt."
          },
          "attempts": {
            "type": "array",
            "description": "Ordered design attempts. Each item is { id?, title?, file? or code?, visualReview? }. File attempts can be replayed by Studio build records.",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "file": {
                  "type": "string"
                },
                "code": {
                  "type": "string"
                },
                "visualReview": {
                  "type": "object",
                  "description": "Evidence from the reviewing agent after rendering/opening screenshots. Accepted reviews must include screenshotPath, concrete findings, and all required checks passing.",
                  "properties": {
                    "accepted": {
                      "type": "boolean"
                    },
                    "screenshotPath": {
                      "type": "string"
                    },
                    "findings": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "checks": {
                      "type": "array",
                      "description": "Required checklist entries: main-object-count, proportions-match-reference, required-visible-features, no-stray-or-floating-geometry, attachment-plausibility, semantic-orientation-alignment, canonical-views-physically-coherent.",
                      "items": {
                        "type": "object",
                        "properties": {
                          "code": {
                            "type": "string"
                          },
                          "passed": {
                            "type": "boolean"
                          },
                          "finding": {
                            "type": "string"
                          },
                          "screenshotPath": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "code",
                          "passed",
                          "finding"
                        ]
                      }
                    }
                  },
                  "required": [
                    "accepted",
                    "findings"
                  ]
                }
              }
            }
          },
          "assembly": {
            "type": "string"
          },
          "preserveInterfaces": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "External mates, connector refs, part names, or behavioral interfaces the agent must preserve between attempts."
          },
          "includePoseEnvelope": {
            "type": "boolean",
            "description": "Forwarded to review_cad. Default true."
          },
          "includeInterference": {
            "type": "boolean",
            "description": "Forwarded to review_cad. Default true."
          },
          "samplesPerMate": {
            "type": "integer",
            "minimum": 1,
            "description": "Pose-envelope samples per declared-limit mate. 1 (default) = corners only; >=3 adds uniform interior points between min and max. Total samples per non-locked mate = samplesPerMate."
          },
          "combinatorial": {
            "type": "boolean",
            "description": "Sample all 2^N limit-corner combinations across mates with declared limits. Capped at 8 mates with limits; combine with samplesPerMate for both interior coverage and worst-pose detection. Default false."
          },
          "epsilonMm3": {
            "type": "number",
            "description": "Forwarded to review_cad."
          },
          "trackConnectors": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Connector refs to track across sampled poses."
          },
          "stopOnPass": {
            "type": "boolean",
            "description": "Stop after the first attempt that is functional and passes the quality gate. Default true."
          },
          "consensus": {
            "type": "boolean",
            "description": "Best-of-N by geometric consensus. When true, attempts are N independent candidates for the SAME goal (not a repair sequence): all are reviewed (stopOnPass ignored), all scripts are executed, candidates without a valid solid are dropped, and the candidate whose geometry agrees most with the others (medoid by symmetric Chamfer distance, same model frame) is selected. Ties go to more gates passed, then the shorter script. Returns consensus { chosenIndex, chosenAttemptId, scores, distances, reason }; ok / finalAttemptId / nextActionPrompt describe the selected candidate. Default false."
          },
          "autoRevise": {
            "type": "boolean",
            "description": "When true (default), failing attempts with repairable feature diagnostics (boolean miss, oversized fillet, …) run bounded repair_script and attach revisionAssist.suggestedPatches / autoApplied.suggestedCode. Set false to skip the extra repair pass (hints-only). Does not autonomously rewrite full CAD models."
          },
          "requireVisualReview": {
            "type": "boolean",
            "description": "Require screenshot-backed visualReview with structured checks before accepting an attempt. Default true; set false only for explicit non-visual batch checks."
          },
          "requirePhysicalAcceptance": {
            "type": "boolean",
            "description": "Require declared physicalUseCase common-pose reachability and pose-bound quasi-static certification before accepting an attempt. Design-loop also enables this automatically when an attempt script calls physicalUseCase(...)."
          },
          "allowReviewWarnings": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Warning diagnostic codes the original prompt explicitly allows. Other review warnings keep the loop iterating even if review_cad is functionally ok."
          },
          "requirements": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Call-time external requirements ([{ name, predicate }]) every attempt is graded against, in the same ledger as script require(). Predicate shape: { metric, a?, b?, op, limit, tolerance?, density? }; operands: { kind: body | faces | edges | part, ref, query? }. A failing or not-evaluated requirement blocks the attempt even with no expert geometry."
          },
          "outputRecordPath": {
            "type": "string",
            "description": "Optional JSON path to write a Studio-compatible build record."
          },
          "recordTitle": {
            "type": "string",
            "description": "Optional title for the build record."
          }
        },
        "required": [
          "goal",
          "attempts"
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "goal": {
            "type": "string",
            "description": "Echoed design goal."
          },
          "finalAttemptId": {
            "type": "string"
          },
          "attempts": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Per-attempt review results (includes revisionAssist when failed)."
          },
          "record": {
            "type": "object",
            "additionalProperties": true,
            "description": "Studio-compatible build record (when requested)."
          },
          "outputRecordPath": {
            "type": "string"
          },
          "recordUrl": {
            "type": "string"
          },
          "nextActionPrompt": {
            "type": "string"
          },
          "convergence": {
            "type": "object",
            "additionalProperties": true,
            "description": "Present when trailing failures share a signature (escalate)."
          },
          "revisionAssist": {
            "type": "object",
            "additionalProperties": true,
            "description": "Structured revision assist from the last failing attempt: hints, suggestedPatches (AST diffs), optional autoApplied.suggestedCode when repair_script cleared a repairable diagnostic. Honest scope — not full autonomous CAD rewrite."
          }
        },
        "required": [
          "ok",
          "goal",
          "attempts"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "flatten_pattern",
      "description": "Use this when you need the unfolded flat pattern of a bent sheet-metal part. Return the unfolded 2D flat-pattern of a bent sheet-metal Shape as a Region (outer polyline + holes + bend lines + sketch plane). Any number of parallel bends; crossing bends need corner relief. Pass { file } or { code }; optional { featureId } to pick a specific Shape.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "file": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "featureId": {
            "type": "string"
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "region": {
            "type": "object",
            "additionalProperties": true,
            "description": "Unfolded flat-pattern Region (outer polyline + holes + bend lines + plane)."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        },
        "required": [
          "ok",
          "diagnostics"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "evaluate_sdf",
      "description": "Use this when you need to sample a signed-distance field at a point. Sample the signed distance from an in-script sdf.* field at a 3D point. Returns { distance, inside, aabb, kind }. Distance is in mm; negative = inside the surface, 0 = exactly on the surface, positive = outside. Use this to verify SDF composition before calling sdf.materialize (which is the expensive step). The script must bind the SdfField via sdf.bind('<name>', field) and pass that name as fieldName. Hint: pass either { file } or { code }, plus { fieldName, point: [x,y,z] }.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "file": {
            "type": "string",
            "description": "Path to a .kcad.ts script file."
          },
          "code": {
            "type": "string",
            "description": "Inline kernelCAD script source."
          },
          "fieldName": {
            "type": "string",
            "description": "sdf.bind binding name holding the SdfField."
          },
          "point": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "minItems": 3,
            "maxItems": 3,
            "description": "Sample point [x, y, z] in mm."
          }
        },
        "required": [
          "fieldName",
          "point"
        ]
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "distance": {
            "type": "number",
            "description": "Signed distance in mm; negative = inside (success)."
          },
          "inside": {
            "type": "boolean",
            "description": "Whether the point is inside the surface (success)."
          },
          "aabb": {
            "type": "object",
            "additionalProperties": true,
            "description": "Axis-aligned bounding box of the field (success)."
          },
          "kind": {
            "type": "string",
            "description": "SDF field kind (success)."
          },
          "error": {
            "type": "string"
          },
          "errorCode": {
            "type": "string"
          },
          "hint": {
            "type": "string"
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "capture_animation",
      "description": "Use this when you need to render a script's animation timeline to a video, or a 360° turntable of a model for sharing. Capture a kernelCAD script's animationView({...}) timeline to an MP4 (ffmpeg) or a PNG frame sequence, verifying the sampled poses for part interference. FILE ONLY: pass { file } (a .kcad.ts path) — there is no { code } mode, because the capture engine renders from a file on disk (its relative lib.fromSTEP imports resolve against the script directory). MP4 by default; pass { frames_dir } to write frame-0000.png... and skip ffmpeg entirely (mutually exclusive with output_path). Animation-pose interference verification runs by default (keyframe times + segment midpoints) BEFORE any browser/ffmpeg cost; { no_verify: true } skips it and { verify_every: n } additionally samples every n-th frame time. Pass { focus } or { hide } (arrays of feature ids or assembly part names, mutually exclusive) to isolate parts in the rendered frames — same semantics as `kernelcad render --focus/--hide`; visibility is render-only and does NOT affect the pose verification. Collisions DO NOT fail the call — the artifact is still written as evidence with ok: true; read verified: false + the collisions[] array. TURNTABLE MODE: pass { turntable: true } for a seamless 360° orbit of the model (no animationView record needed) — a share-ready loop for a README, social post or product page. It uses the 'publish' studio look by default (same as render_preview preset: 'publish': key/fill/rim lights, soft contact shadow, clean backdrop, 30° lens, constant auto-framing over the whole orbit, light rig turns with the camera); { preset: 'default' } keeps the engineering look. Knobs: width/height (default 1080×1080, max 2048, even for MP4), duration_ms (one revolution, default 6000), fps (default 30), elevation_deg (default 22), background ('white' default, 'light', 'dark', 'black', '#rrggbb', or 'transparent' with frames_dir only), shadow (default true), environment. output_path ending in .gif writes a looping GIF; otherwise MP4. Frame i sits at az 30° + 360°·i/N (the 360° endpoint is excluded, so the loop is seamless). A turntable has no poses to verify: it reports verify_skipped: true. ENVIRONMENT: needs playwright chromium (npx playwright install chromium) and ffmpeg for MP4/GIF (frames_dir needs neither); the bundled static player is served automatically, no dev server required. Returns { ok, output_path, frame_count, duration_ms, fps, verified, verify_skipped?, collisions: [{ t_ms, a, b, volume_mm3 }], diagnostics }.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "file": {
            "type": "string",
            "description": "Path to a .kcad.ts script with an animationView({...}) record (any script in turntable mode). Required (no inline { code } mode)."
          },
          "output_path": {
            "type": "string",
            "description": "MP4 output path (.gif → looping GIF); default <scriptDir>/<basename>-animation.mp4 (-turntable.mp4 in turntable mode). Mutually exclusive with frames_dir."
          },
          "frames_dir": {
            "type": "string",
            "description": "PNG-sequence mode directory: write frame-0000.png... and skip ffmpeg. Mutually exclusive with output_path."
          },
          "fps": {
            "type": "number",
            "description": "Override the animationView record's fps."
          },
          "no_verify": {
            "type": "boolean",
            "description": "Skip the animation-pose interference verification (default: verify on).",
            "default": false
          },
          "verify_every": {
            "type": "integer",
            "minimum": 1,
            "description": "Additionally verify at every n-th frame time of the fps schedule (unioned with the keyframe sample set)."
          },
          "focus": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Show only matching feature ids / assembly part names in the rendered frames. Mutually exclusive with hide. Render-only; does not affect pose verification."
          },
          "hide": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Hide matching feature ids / assembly part names in the rendered frames. Mutually exclusive with focus. Render-only; does not affect pose verification."
          },
          "turntable": {
            "type": "boolean",
            "description": "Seamless 360° orbit of the model instead of the animationView timeline.",
            "default": false
          },
          "preset": {
            "type": "string",
            "enum": [
              "default",
              "publish"
            ],
            "description": "Turntable look: 'publish' (default; studio product shot) or 'default' (engineering look)."
          },
          "width": {
            "type": "integer",
            "minimum": 64,
            "maximum": 2048,
            "description": "Turntable frame width in px (default 1080; even for MP4)."
          },
          "height": {
            "type": "integer",
            "minimum": 64,
            "maximum": 2048,
            "description": "Turntable frame height in px (default 1080; even for MP4)."
          },
          "duration_ms": {
            "type": "number",
            "minimum": 500,
            "maximum": 60000,
            "description": "Turntable: one full revolution in ms (default 6000)."
          },
          "elevation_deg": {
            "type": "number",
            "minimum": -89,
            "maximum": 89,
            "description": "Turntable: camera elevation above the horizon in degrees (default 22)."
          },
          "background": {
            "type": "string",
            "description": "Turntable + publish: 'white' (default), 'light', 'dark', 'black', '#rrggbb', or 'transparent' (frames_dir only — MP4/GIF have no usable alpha)."
          },
          "shadow": {
            "type": "boolean",
            "description": "Turntable + publish: soft contact shadow under the model (default true)."
          },
          "environment": {
            "type": "string",
            "description": "Turntable: HDRI environment override ('studio', 'softbox', 'neutral', 'outdoor', 'warehouse', a URL, or 'none')."
          }
        },
        "required": [
          "file"
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": true
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "output_path": {
            "type": "string",
            "description": "Written MP4 path (MP4 mode)."
          },
          "frame_count": {
            "type": "number"
          },
          "duration_ms": {
            "type": "number"
          },
          "fps": {
            "type": "number"
          },
          "verified": {
            "type": "boolean",
            "description": "Whether pose-interference verification passed."
          },
          "verify_skipped": {
            "type": "boolean"
          },
          "collisions": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Colliding poses { t_ms, a, b, volume_mm3 }."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "error": {
            "type": "string"
          },
          "errorCode": {
            "type": "string"
          },
          "errorHint": {
            "type": "string"
          },
          "failure_kind": {
            "type": "string"
          }
        },
        "required": [
          "ok",
          "diagnostics"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "render_preview",
      "description": "Use this when you need to LOOK at a kernelCAD model — render its script to deterministic PNG views for visual self-check (the visual half of the evaluate → render → inspect → fix loop), with NO studio or dev server required. Pass { code } (inline source) or { file } (a .kcad.ts path), exactly one. Renders the canonical engineering views (front, right, top, iso — pass { views } for a subset, e.g. [\"iso\"] for fastest iteration) plus an optional { pose: \"<az>,<el>\" } arbitrary camera angle (degrees; az=0,el=0 is front, +az rotates CCW around +Z, +el lifts the camera). NO STUDIO / DEV-SERVER REQUIRED: a prebuilt static player (dist/headless-player) is served from an ephemeral local port automatically; a running studio dev server is used as fallback, and { base_url } forces one. The only environment dependency is playwright chromium (npx playwright install chromium). Pass { focus } or { hide } (arrays of feature ids or assembly part names, mutually exclusive) to isolate parts — same semantics as `kernelcad render --focus/--hide`. Pass { section: { axis, position, flip? } } to cut a cross-section and inspect INTERIOR geometry (wall thickness, internal pockets, whether a bore runs through) rather than only the outer shell. Pass { explode: { factor, mode? } } to pull a multi-part assembly apart (mode: \"mate-axis\" default, or \"radial\") using the same mesher as `kernelcad render --explode` — requires assembly.model()/solvedModel(). PNGs are written to { out_dir } (default: a fresh temp session directory) and returned as absolute paths with per-view camera descriptions (kernelCAD is Z-up). Mechanism truth runs first, same protocol as `kernelcad render`: a broken mechanism still renders but every tile is watermarked MECHANISM BROKEN (KERNELCAD_RENDER_STRICT=1 refuses instead); read { mechanism, mechanism_failure_codes }. The probe runs full BREP interference sweeps and can dominate latency on large assemblies — pass { no_mechanism_check: true } for fast iteration (the preview then reports mechanism: \"unverified\"; ignored under strict mode). Pass { overlay: 'zebra' | 'curvature' | 'continuity' } for a surface-quality visualisation (zebra stripes from vertex normals, curvature as vertex colours, continuity edges coloured by G0/G1/G2/broken) — numbers come from inspect({ of: 'continuity' | 'curvature' }); the overlay is the picture. PUBLISH PRESET: pass { preset: 'publish' } for a share-ready studio product shot (gallery tile, social post, README image, product page): key/fill/rim lights + room reflections, soft contact shadow, clean backdrop ({ background: 'white' (default) | 'light' | 'dark' | 'black' | '#rrggbb' | 'transparent' } — transparent gives a PNG with alpha), { shadow: false } to drop the shadow, 2× supersampled anti-aliasing, 30° lens, the model silhouette centred and auto-framed with ~11% air (a script's setCameraTarget is ignored), per-part colours/materials as authored, no watermark. With no views/pose it renders ONE image named 'hero' (3/4 front-right, az=30°, el=22°) at 1600×1200; width/height go up to 2048; views/pose still work under the preset. Output is deterministic for the same input. For a 360° loop use capture_animation({ turntable: true }). INSPECTION SHEET: { sheet: true } renders all seven views (iso, front, back, left, right, top, bottom) and adds one labelled image named 'sheet' tiling them — do not call a model done because it compiled; call it done when every tile of the sheet matches the request. Returns { ok, images: [{ name, path, description }], out_dir, bounds, mechanism, render_source, render_ms, diagnostics }. PATHS ARE LOCAL to the machine running the MCP server — local stdio clients read them directly; hosted/remote clients should use open_in_studio instead.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Inline kernelCAD script source. Mutually exclusive with file. Relative imports resolve against a temp dir — use file for scripts with relative lib.fromSTEP(...) imports."
          },
          "file": {
            "type": "string",
            "description": "Path to a .kcad.ts script on disk. Mutually exclusive with code."
          },
          "views": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "front",
                "back",
                "left",
                "right",
                "top",
                "bottom",
                "iso"
              ]
            },
            "description": "Views to render (default: front, right, top, iso; all seven with sheet). Fewer views = faster."
          },
          "sheet": {
            "type": "boolean",
            "description": "Also write one labelled image 'sheet' tiling every rendered view. With no views it renders all seven (adds back, left, bottom) — use it before calling a model done, so a missing cutout on the back or underside is not missed.",
            "default": false
          },
          "pose": {
            "type": "string",
            "description": "Extra arbitrary camera pose '<az>,<el>' in degrees, e.g. '30,20'."
          },
          "focus": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Show only matching feature ids / assembly part names. Mutually exclusive with hide."
          },
          "hide": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Hide matching feature ids / assembly part names. Mutually exclusive with focus."
          },
          "out_dir": {
            "type": "string",
            "description": "Directory for the PNGs (created if missing). Default: a fresh temp session dir."
          },
          "width": {
            "type": "integer",
            "minimum": 64,
            "maximum": 2048,
            "description": "Per-view tile width in px (default 768; 1600 under preset: 'publish')."
          },
          "height": {
            "type": "integer",
            "minimum": 64,
            "maximum": 2048,
            "description": "Per-view tile height in px (default 768; 1200 under preset: 'publish')."
          },
          "environment": {
            "type": "string",
            "description": "HDRI environment override: preset ('studio', 'softbox', 'neutral', 'outdoor', 'warehouse'), a URL, or 'none' for the default three-light rig."
          },
          "shading": {
            "type": "string",
            "enum": [
              "smooth",
              "flat"
            ],
            "description": "Mesh shading: 'smooth' uses the kernel's vertex normals (default); 'flat' uses face normals to expose tessellation / surface wobble."
          },
          "screenshot_timeout_ms": {
            "type": "integer",
            "minimum": 1000,
            "maximum": 600000,
            "description": "Playwright screenshot deadline in milliseconds. Default leaves Playwright's 30 s in place; raise it for heavy lofts or a slow machine."
          },
          "no_watermark": {
            "type": "boolean",
            "description": "Suppress the kernelCAD version watermark.",
            "default": false
          },
          "no_mechanism_check": {
            "type": "boolean",
            "description": "Skip the mechanism-truth probe for fast iteration on large assemblies; the preview reports mechanism: 'unverified'. Ignored under KERNELCAD_RENDER_STRICT=1.",
            "default": false
          },
          "base_url": {
            "type": "string",
            "description": "Advanced: force a specific render server (e.g. a running studio dev server) instead of the bundled static player."
          },
          "section": {
            "type": "object",
            "description": "Cut the model with one axis-aligned section plane to inspect INTERIOR structure (wall thickness, internal pockets, whether a bore runs through) instead of only the outer shell. position is in mm along the axis (kernelCAD Z-up frame); flip keeps the +axis side (default keeps the -axis side).",
            "properties": {
              "axis": {
                "type": "string",
                "enum": [
                  "x",
                  "y",
                  "z"
                ]
              },
              "position": {
                "type": "number"
              },
              "flip": {
                "type": "boolean",
                "default": false
              }
            },
            "required": [
              "axis",
              "position"
            ],
            "additionalProperties": false
          },
          "explode": {
            "type": "object",
            "description": "Pull a multi-part assembly apart for the preview. factor ≥ 0 scales spacing by part size; mode is 'mate-axis' (default, along parent mate/joint axes) or 'radial' (away from the assembly centroid). Requires the script to return assembly.model() / solvedModel().",
            "properties": {
              "factor": {
                "type": "number",
                "minimum": 0
              },
              "mode": {
                "type": "string",
                "enum": [
                  "radial",
                  "mate-axis"
                ]
              }
            },
            "required": [
              "factor"
            ],
            "additionalProperties": false
          },
          "overlay": {
            "type": "string",
            "enum": [
              "zebra",
              "curvature",
              "continuity"
            ],
            "description": "Surface-quality overlay: 'zebra' (reflection stripes), 'curvature' (Gaussian vertex colours), 'continuity' (edges coloured G2 green / G1 yellow / G0 orange / broken red). Built as coloured STL bands through this same pipeline."
          },
          "preset": {
            "type": "string",
            "enum": [
              "default",
              "publish"
            ],
            "description": "Render look: 'default' (engineering review) or 'publish' (studio product shot for sharing; one 'hero' image unless views/pose are given)."
          },
          "background": {
            "type": "string",
            "description": "preset 'publish' only: 'white' (default), 'light', 'dark', 'black', 'transparent' (PNG alpha), or '#rrggbb'."
          },
          "shadow": {
            "type": "boolean",
            "description": "preset 'publish' only: soft contact shadow under the model (default true)."
          }
        }
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": true
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "sceneSummary": {
            "type": "object",
            "properties": {
              "valid": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "BREP validity, independent of DFM/mechanism/tool success; null if unchecked."
              },
              "volume": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Volume in mm³; assembly parts summed, including overlaps."
              },
              "faceCount": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "BREP faces, summed per assembly part; not mesh triangles."
              },
              "size": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3,
                "description": "Conservative world AABB size [x,y,z] in mm."
              }
            },
            "required": [
              "valid",
              "volume",
              "faceCount",
              "size"
            ],
            "additionalProperties": false
          },
          "ok": {
            "type": "boolean",
            "description": "Whether the preview rendered."
          },
          "images": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Rendered tiles { name, path, description } — absolute local PNG paths with per-view camera orientation (kernelCAD is Z-up)."
          },
          "out_dir": {
            "type": "string",
            "description": "Directory holding the PNGs (session temp dir unless out_dir was given)."
          },
          "bounds": {
            "type": "object",
            "additionalProperties": true,
            "description": "Model AABB in mm { min, max } the camera was fit to (success)."
          },
          "mechanism": {
            "type": "string",
            "description": "Mechanism-truth verdict: 'real' | 'broken' | 'unverified'."
          },
          "mechanism_failure_codes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "De-duplicated failure codes when mechanism is 'broken'."
          },
          "render_source": {
            "type": "string",
            "description": "Lane that served the render: 'static-player' | 'dev-server' | 'explicit'."
          },
          "render_ms": {
            "type": "number",
            "description": "Wall-clock render time in ms (provisioning + browser + captures)."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "error": {
            "type": "string"
          },
          "errorCode": {
            "type": "string"
          },
          "errorHint": {
            "type": "string"
          }
        },
        "required": [
          "ok",
          "images",
          "diagnostics"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "resolve_assumptions",
      "description": "Use this when you need to confirm or override the open facts in an assumption ledger from trace_from_image (missing scale, inferred/assumed values) before committing geometry built from a reference photo. Reads the persisted `<model>.ledger.json` at `ledgerPath`, applies each resolution — `{ id, confirm: true }` to accept a fact as-is, or `{ id, value }` to override it — rewrites the ledger file, and returns the updated ledger plus `paramOverrides` (factId -> value) to feed straight into `set_param`. Pair with the `kernelcad-from-reference` skill.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "ledgerPath": {
            "type": "string",
            "description": "Path to the `<model>.ledger.json` file persisted alongside the traced source."
          },
          "resolutions": {
            "type": "array",
            "description": "One resolution per ledger fact id to act on.",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string",
                  "description": "Matches a `facts[].id` in the ledger."
                },
                "value": {
                  "type": [
                    "string",
                    "number",
                    "boolean",
                    "array",
                    "object"
                  ],
                  "description": "Overrides the fact's value; marks it `overridden`."
                },
                "confirm": {
                  "type": "boolean",
                  "description": "Accepts the fact as-is; marks it `confirmed`."
                }
              },
              "required": [
                "id"
              ]
            }
          }
        },
        "required": [
          "ledgerPath",
          "resolutions"
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "ledger": {
            "type": "object",
            "additionalProperties": true,
            "description": "The ledger after applying resolutions (present on success)."
          },
          "paramOverrides": {
            "type": "object",
            "additionalProperties": true,
            "description": "factId -> value for every resolved fact with a value; feed into set_param."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        },
        "required": [
          "ok",
          "paramOverrides",
          "diagnostics"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "run_fea",
      "description": "Use this when you need to know whether a part will hold a load. Runs a linear-static structural study and returns evidence — peak von Mises stress (MPa), peak displacement (mm), the minimum safety factor against the material yield (taken away from the clamp-singular edges of the fixed faces; the raw clamp-edge peak is reported separately as peakAtSupportMPa), per-region hot spots named by @kc[...] face ref, mesh trust flags, an equilibrium residual, and (CalculiX only) stress-heatmap PNG paths.\nThe study is EITHER declared in the script with `shape.feaStudy({ material, fixed, loads, meshSize?, minSafetyFactor? })` OR passed on the call against the shape the script returns: { code: 'return box(100, 20, 10);', material: 'aluminum-6061', fixed: { atX: 0 }, loads: [{ faces: { atX: 100 }, force: [0, 0, -200] }] }. Faces are a FaceQuery ({ atX | atY | atZ, byNormal: 'Z', ofSurfaceType, near: [x,y,z], ... }; with near it names the ONE matching face nearest the point), a face label ('top', 'bottom', 'left', 'right', 'front', 'back'; it must name ONE face — after a boolean 'top' can be several, which is an error listing them) or an @kc[...] ref. Force is the TOTAL [Fx, Fy, Fz] in N on those faces (a scalar force + direction is accepted). Materials: mild-steel, aluminum-6061, pla, petg, abs, nylon (aliases steel, aluminum), or { E, nu, yield } in MPa.\nSolver (`solver`, default 'auto'): CalculiX + gmsh quadratic tets when that toolchain is installed; otherwise the built-in in-process voxel solver (8-node incompatible-mode bricks), which needs nothing installed and is marked summary.solver 'in-process-voxel' with trust.meshTrusted false — an estimate (accurate for prismatic bending, approximate at curved faces and notches), never a verified pass. solver: 'calculix' fails up front with fea.solver.unavailable and the install command when the toolchain is absent.\nAlso: `study` (a declared study name; default the last), `output_dir` (keeps the deck / summary JSON), `mesh_size` (mm, overrides the study for this run), `heatmaps: false` for a numbers-only run. CalculiX mesh refinement is automatic: when the stress is untrusted only because the solver's error estimate is high, it re-solves once at 0.75x the element size (inside the element budget), with summary.refinement listing each pass. `refine: false` solves once.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "file": {
            "type": "string",
            "description": "Path to a .kcad.ts script declaring at least one feaStudy."
          },
          "code": {
            "type": "string",
            "description": "Inline kernelCAD script source (mutually exclusive with file)."
          },
          "study": {
            "type": "string",
            "description": "Name of the declared study to run; defaults to the last declared one."
          },
          "material": {
            "type": [
              "string",
              "object"
            ],
            "description": "Inline study: material grade name (e.g. 'aluminum-6061') or { E, nu, yield } in MPa."
          },
          "fixed": {
            "type": [
              "string",
              "object"
            ],
            "description": "Inline study: faces held fixed — a FaceQuery like { atX: 0 }, a face label like 'bottom', or an @kc[...] ref."
          },
          "loads": {
            "type": "array",
            "description": "Inline study: loads, each { faces, force: [Fx, Fy, Fz] } — total force in N on those faces.",
            "items": {
              "type": "object"
            }
          },
          "min_safety_factor": {
            "type": "number",
            "description": "Inline study: required minimum safety factor; below it the call fails with fea.safety-factor.below-min."
          },
          "solver": {
            "type": "string",
            "enum": [
              "auto",
              "calculix",
              "in-process"
            ],
            "description": "'auto' (default): CalculiX when installed, else in-process. 'calculix': require it. 'in-process': always the built-in voxel solver."
          },
          "output_dir": {
            "type": "string",
            "description": "Directory for the solver deck, results, summary JSON and heatmap PNGs."
          },
          "mesh_size": {
            "type": "number",
            "description": "Target element size in mm, overriding the study for this run."
          },
          "heatmaps": {
            "type": "boolean",
            "description": "Render stress heatmap PNGs (default true)."
          },
          "refine": {
            "type": "boolean",
            "description": "One automatic finer pass (0.75x element size) when the stress is untrusted, inside the element budget (default true). false: one solve at mesh_size."
          },
          "mesh_timeout_ms": {
            "type": "number",
            "description": "Wall-clock budget for meshing (default 120000)."
          },
          "solve_timeout_ms": {
            "type": "number",
            "description": "Wall-clock budget for the solve (default 300000)."
          }
        }
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": true
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "description": "False when the study violated its declared minSafetyFactor, a selector did not resolve, the solve failed, or solver:'calculix' was required and the toolchain is missing."
          },
          "summary": {
            "type": "object",
            "additionalProperties": true,
            "description": "Solved evidence: solver ('calculix' or 'in-process-voxel'), maxVonMisesMPa, maxVonMisesAt, maxDisplacementMm, maxDisplacementAt, minSafetyFactor (+ minSafetyFactorRequired), nodeCount/elementCount/meshSizeMm, quality (minSICN, meanSICN, lowQualityCount), maxStressErrorPercent (high-stress region), trust { meshTrusted, reasons }, hotSpots [{ region, maxVonMisesMPa, nodeId, at, safetyFactor }]; the stress values, safety factor and hot spots exclude the support zone next to fixed-face edges (governingField), whose clamp-singular raw peak is reported as peakAtSupportMPa / peakAtSupportAt / peakAtSupportRegion with supportAdjacentNodeCount and supportZoneRadiusMm; appliedForceN / reactionForceN / equilibriumResidual, meshMs / solveMs."
          },
          "toolchain": {
            "type": "object",
            "additionalProperties": true,
            "description": "{ missing[], hint } — present when solver:'calculix' was required and CalculiX / gmsh are not installed."
          },
          "images": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Absolute PNG paths of the rendered stress heatmap."
          },
          "legend": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Heatmap colour bands { color, fromMPa, toMPa } — the scale the PNGs are drawn on."
          },
          "out_dir": {
            "type": "string",
            "description": "Directory holding the summary JSON, solver deck and heatmap PNGs."
          },
          "artifacts": {
            "type": "object",
            "additionalProperties": true,
            "description": "Absolute paths of the BREP geometry handoff, .inp deck, .frd results and mesh JSON, for hand reproduction."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "fea.* diagnostics raised by the run."
          },
          "error": {
            "type": "string"
          },
          "errorCode": {
            "type": "string"
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "fea_summary",
      "description": "Use this when you need a structural check's context without paying for a solve. Read-only: returns the stored summary of a previous run_fea (pass the same `output_dir`), whether the CalculiX + gmsh toolchain is available on this machine (with the install command when it is not; run_fea then uses its in-process voxel solver — toolchain.default_solver says which), and the FEA material table with real E / Poisson / yield numbers so a grade is chosen against data rather than from memory. Never meshes, solves, or writes.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "output_dir": {
            "type": "string",
            "description": "Directory a previous run_fea wrote to; omit for toolchain status + material table only."
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "summary": {
            "type": "object",
            "additionalProperties": true,
            "description": "Stored summary of a previous run_fea in output_dir, when present."
          },
          "toolchain": {
            "type": "object",
            "additionalProperties": true,
            "description": "{ available, ccx?, gmshVersion?, missing[], hint? } — whether a study can run here and how to fix it if not."
          },
          "materials": {
            "type": "object",
            "additionalProperties": true,
            "description": "Named grade -> { E (MPa), nu, yield (MPa) }."
          },
          "material_names": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Accepted material grade names."
          },
          "error": {
            "type": "string"
          },
          "errorCode": {
            "type": "string"
          }
        },
        "required": [
          "ok",
          "toolchain",
          "materials",
          "material_names"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "send_to_printer",
      "description": "Use this when you need to upload a .gcode file (e.g. written by export with target: \"model\", format: \"gcode\") to a real network printer and, by default, start the print. protocol: 'octoprint' (POST /api/files/local with an X-Api-Key), 'moonraker' (Klipper's POST /server/files/upload), or 'bambu-lan' (Bambu Lab LAN-mode: FTPS implicit-TLS upload on port 990 as user 'bblp' with the printer's LAN access code, then an MQTT print-start command on port 8883 — requires access_code and, unless start_print is false, serial). bambu-lan uploads a .gcode.3mf print project (the printer prints 3MF projects, not bare G-code): the G-code goes in as Metadata/plate_1.gcode, inside the model 3MF from export format '3mf' when model_3mf_path is given (use options { arrange: 'plate', slicer: 'bambu' } so the printer shows the same named, coloured parts), else inside a minimal 3MF shell; the file name always ends in .3mf ('part.gcode' -> 'part.gcode.3mf'). Optional printer (a bundled profile id, the same ids as the export 3mf/gcode options.printer) is checked against protocol before anything is read or sent: an unknown id is refused with the list of valid ids, 'bambu-lan' needs a Bambu Lab profile and a Bambu Lab profile needs 'bambu-lan'. Pass { dry_run: true } to validate connectivity/authentication only, without uploading or starting a print. Never logs or echoes api_key/access_code.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "gcode_path": {
            "type": "string",
            "description": "Path to the .gcode file on disk."
          },
          "protocol": {
            "type": "string",
            "enum": [
              "octoprint",
              "moonraker",
              "bambu-lan"
            ]
          },
          "host": {
            "type": "string",
            "description": "Printer hostname or IP."
          },
          "port": {
            "type": "number",
            "description": "Override the protocol default port."
          },
          "api_key": {
            "type": "string",
            "description": "OctoPrint API key (Settings -> API)."
          },
          "access_code": {
            "type": "string",
            "description": "Bambu LAN-mode access code (printer settings -> LAN Only Mode)."
          },
          "serial": {
            "type": "string",
            "description": "Bambu printer serial number (required to start a print unless start_print is false)."
          },
          "model_3mf_path": {
            "type": "string",
            "description": "bambu-lan only: model .3mf from export format '3mf' to package the G-code into (the uploaded .gcode.3mf)."
          },
          "printer": {
            "type": "string",
            "enum": [
              "generic-fdm",
              "bambu-a1-mini",
              "bambu-a1",
              "bambu-p1s",
              "bambu-p1p",
              "bambu-x1c",
              "bambu-x1e",
              "bambu-h2d",
              "bambu-h2s",
              "prusa-mini-plus",
              "prusa-mk4s",
              "prusa-core-one",
              "prusa-xl",
              "creality-ender-3-v3",
              "creality-k1",
              "creality-k1-max",
              "creality-k2-plus",
              "elegoo-neptune-4-pro",
              "anycubic-kobra-3",
              "voron-2.4-250",
              "voron-2.4-300",
              "voron-2.4-350",
              "ultimaker-s5"
            ],
            "description": "Printer profile id; checked against protocol before upload. List them with 'kernelcad print printers'."
          },
          "filename": {
            "type": "string",
            "description": "Uploaded file name (default: 'kernelcad.gcode'; bambu-lan appends '.3mf')."
          },
          "start_print": {
            "type": "boolean",
            "description": "Start the print immediately after upload (default: true)."
          },
          "dry_run": {
            "type": "boolean",
            "description": "Validate connectivity/auth only; never uploads or starts a print."
          }
        },
        "required": [
          "gcode_path",
          "protocol",
          "host"
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": true
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "uploaded_path": {
            "type": "string",
            "description": "Path/name the G-code (bambu-lan: the .gcode.3mf print file) was stored under on the printer."
          },
          "dry_run": {
            "type": "boolean",
            "description": "True when only connectivity/auth was validated (no upload, no print start)."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "error": {
            "type": "string"
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "repair_script",
      "description": "Use this when evaluate_script reported an error and you want the fix applied rather than described. Takes the candidates why_did_this_fail derives for a diagnostic, applies them one at a time, re-evaluates after each, and keeps the first that clears the diagnostic without introducing new errors. Never edits outside the repair region (failing feature statement + its input statements + the param() lines it reads) — an out-of-region patch is refused with tool.repair.out-of-region. Returns the repaired source in `new_code` (the caller persists it), a unified `diff`, and before/after health maps. Pass { file? | code?, diagnostic?: '<id>'|'first-error', strategy?: 'apply-first'|'try-all'|'dry-run', max_attempts?: number }.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "file": {
            "type": "string",
            "description": "Path to a .kcad.ts script file."
          },
          "code": {
            "type": "string",
            "description": "Inline kernelCAD script source."
          },
          "diagnostic": {
            "type": "string",
            "description": "Diagnostic id from why_did_this_fail's `targetDiagnosticId` / `candidates[].diagnosticId`, or 'first-error' (default) for the first error-severity diagnostic."
          },
          "strategy": {
            "type": "string",
            "enum": [
              "apply-first",
              "try-all",
              "dry-run"
            ],
            "description": "'try-all' (default) walks candidates until one clears the diagnostic; 'apply-first' applies only the top candidate and reports what it did; 'dry-run' previews every candidate patch without evaluating."
          },
          "max_attempts": {
            "type": "integer",
            "minimum": 1,
            "maximum": 10,
            "description": "Upper bound on candidates attempted (default 3). Ignored by apply-first and dry-run."
          }
        }
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "description": "Whether a candidate cleared the target diagnostic without new errors."
          },
          "strategy": {
            "type": "string",
            "enum": [
              "apply-first",
              "try-all",
              "dry-run"
            ]
          },
          "target": {
            "type": "object",
            "additionalProperties": true,
            "description": "The diagnostic this run targeted { id, code, featureId?, message }."
          },
          "repairRegion": {
            "type": "object",
            "additionalProperties": true,
            "description": "The line ranges the repair was bound to."
          },
          "candidates": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "candidateStatus": {
            "type": "string",
            "enum": [
              "candidates",
              "no-automatic-candidate"
            ]
          },
          "candidateReason": {
            "type": "string"
          },
          "attempts": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Per-candidate outcome { candidateId, applied, ok?, clearedDiagnostic?, newErrorCodes?, accepted, diagnostic? }."
          },
          "applied": {
            "type": "string",
            "description": "Candidate id that was accepted."
          },
          "new_code": {
            "type": "string",
            "description": "Repaired .kcad.ts source (present when a patch applied). Caller persists it."
          },
          "diff": {
            "type": "string",
            "description": "Unified diff of the accepted patch (dry run: every candidate patch)."
          },
          "before": {
            "type": "object",
            "properties": {
              "sceneSummary": {
                "type": "object",
                "properties": {
                  "valid": {
                    "type": [
                      "boolean",
                      "null"
                    ],
                    "description": "BREP validity, independent of DFM/mechanism/tool success; null if unchecked."
                  },
                  "volume": {
                    "type": [
                      "number",
                      "null"
                    ],
                    "description": "Volume in mm³; assembly parts summed, including overlaps."
                  },
                  "faceCount": {
                    "type": [
                      "integer",
                      "null"
                    ],
                    "description": "BREP faces, summed per assembly part; not mesh triangles."
                  },
                  "size": {
                    "type": [
                      "array",
                      "null"
                    ],
                    "items": {
                      "type": "number"
                    },
                    "minItems": 3,
                    "maxItems": 3,
                    "description": "Conservative world AABB size [x,y,z] in mm."
                  }
                },
                "required": [
                  "valid",
                  "volume",
                  "faceCount",
                  "size"
                ],
                "additionalProperties": false
              }
            },
            "additionalProperties": true,
            "description": "Pre-repair { ok, featureHealth, diagnostics }."
          },
          "after": {
            "type": "object",
            "properties": {
              "sceneSummary": {
                "type": "object",
                "properties": {
                  "valid": {
                    "type": [
                      "boolean",
                      "null"
                    ],
                    "description": "BREP validity, independent of DFM/mechanism/tool success; null if unchecked."
                  },
                  "volume": {
                    "type": [
                      "number",
                      "null"
                    ],
                    "description": "Volume in mm³; assembly parts summed, including overlaps."
                  },
                  "faceCount": {
                    "type": [
                      "integer",
                      "null"
                    ],
                    "description": "BREP faces, summed per assembly part; not mesh triangles."
                  },
                  "size": {
                    "type": [
                      "array",
                      "null"
                    ],
                    "items": {
                      "type": "number"
                    },
                    "minItems": 3,
                    "maxItems": 3,
                    "description": "Conservative world AABB size [x,y,z] in mm."
                  }
                },
                "required": [
                  "valid",
                  "volume",
                  "faceCount",
                  "size"
                ],
                "additionalProperties": false
              }
            },
            "additionalProperties": true,
            "description": "Post-repair { ok, featureHealth, diagnostics }."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "tool.repair.* diagnostics when repair could not complete."
          },
          "error": {
            "type": "string"
          },
          "errorCode": {
            "type": "string"
          }
        },
        "required": [
          "ok",
          "strategy",
          "candidates",
          "attempts"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "sweep_tolerance",
      "description": "Use this when you need to know where and why a design breaks across a tolerance/dimension range, not just whether it builds at one nominal value. Declares one or more param() names with a { values: [...] } list or a { min, max, steps } range (number params are bisected; choice/string params are evaluated as discrete points), re-evaluates the script once per cartesian-product combination (capped at 64 combos — exceeding it truncates to the first 64 and emits kinematic.sweep-tolerance.combo-cap-exceeded), and measures every requirement in the S2 ledger (script require(), dfmSpec, gated FEA, mechanical intent) plus the standard gates on each combo: interference, mounting-hole diameter agreement, and joint-axis binding (all three default on); reachability only when gates.reachable names a tip_link + target. After the coarse grid it bisects each numeric pass/fail transition down to boundaryTolerance and reports the boundary value, the failing side, and the binding requirement/gate names (e.g. \"wall fails below 1.840 mm; binding: wall\"). Returns per-combo verdicts, firstFailure per gate, firstRequirementFailure per requirement, boundaries[], and a coverage statement that says \"checked at N points plus boundaries\", never \"proven\".",
      "inputSchema": {
        "type": "object",
        "properties": {
          "file": {
            "type": "string",
            "description": "Path to a .kcad.ts script file."
          },
          "code": {
            "type": "string",
            "description": "Inline kernelCAD script source."
          },
          "assembly": {
            "type": "string",
            "description": "Assembly name; defaults to the first captured assembly."
          },
          "params": {
            "type": "object",
            "description": "param() name -> { values: [number|string, ...] } or { min, max, steps }."
          },
          "gates": {
            "type": "object",
            "description": "Which standard gates to run per combo.",
            "properties": {
              "interference": {
                "type": "boolean",
                "description": "Default true."
              },
              "mountingHoles": {
                "type": "boolean",
                "description": "Default true."
              },
              "jointAxis": {
                "type": "boolean",
                "description": "Default true."
              },
              "reachable": {
                "type": "object",
                "description": "Runs the reachability gate when set.",
                "properties": {
                  "tipLink": {
                    "type": "string"
                  },
                  "targetPosition": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    },
                    "minItems": 3,
                    "maxItems": 3
                  },
                  "targetOrientation": {
                    "type": "array",
                    "items": {
                      "type": "number"
                    },
                    "minItems": 3,
                    "maxItems": 3
                  }
                },
                "required": [
                  "tipLink",
                  "targetPosition"
                ]
              }
            }
          },
          "boundaryTolerance": {
            "type": "number",
            "description": "Absolute parameter tolerance for boundary bisection. Default 0.001."
          },
          "boundaryBudget": {
            "type": "number",
            "description": "Maximum extra evaluations spent bisecting boundaries. Default 64; 0 skips bisection."
          }
        },
        "required": [
          "params"
        ]
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "description": "Whether every gate and every ledger requirement passed on every evaluated combo."
          },
          "combosEvaluated": {
            "type": "number",
            "description": "Number of combos actually evaluated (capped at 64)."
          },
          "combosCapped": {
            "type": "boolean",
            "description": "True when the full cartesian product exceeded the 64-combo cap."
          },
          "results": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "One entry per evaluated combo: { combo, gates, requirements, verdict, diagnostics }."
          },
          "firstFailure": {
            "type": "object",
            "additionalProperties": true,
            "description": "First failing combo per gate name."
          },
          "firstRequirementFailure": {
            "type": "object",
            "additionalProperties": true,
            "description": "First non-passing combo per ledger requirement name."
          },
          "boundaries": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Bisected pass/fail transitions: { parameter, direction, passValue, failValue, value, failureSide, bindingRequirements, bindingGates, at, evaluations, withinTolerance, exhausted, message }."
          },
          "boundaryEvaluations": {
            "type": "number",
            "description": "Extra evaluations spent on boundary bisection."
          },
          "boundaryBudget": {
            "type": "number",
            "description": "Evaluation budget used for boundary bisection."
          },
          "boundaryTolerance": {
            "type": "number",
            "description": "Absolute parameter tolerance the boundaries were bisected to."
          },
          "coverage": {
            "type": "object",
            "additionalProperties": true,
            "description": "Honest coverage: { points, boundaries, boundaryEvaluations, statement, proven: false }."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Sweep-level diagnostics (combo-cap-exceeded, boundary-budget-exhausted)."
          },
          "error": {
            "type": "string"
          },
          "errorCode": {
            "type": "string"
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "diff_geometry",
      "description": "Use this when you need to know WHAT MATERIAL changed between two versions of a model, not just how much. The deeper sibling of diff_scripts: a volume delta alone is ambiguous (a boss that grew and a pocket that deepened report the same magnitude, and a part that only moved reports zero), so this tool answers it with geometry instead of pixels. Baseline is { baseFile } or { baseCode }; the revised side is either another script ({ file } or { code }) or the SAME script re-lowered with { params } overrides — a bag of declared param() name -> new value, which is the one-script form a parameter sweep actually asks for. Bodies pair by name and fall back to declaration-order positional pairing; anything left over is listed in `unmatched` and raises diff.body.unmatched. Per matched body it returns addedMm3 = volume(revised - base), removedMm3 = volume(base - revised), commonMm3 = volume of the overlap from boolean intersection, exact bbox with min/max/extent deltas, face / edge / hole count deltas (hole counts reuse the cylindrical-hole detector), maxDeviationMm (two-sided discrete Hausdorff distance between the two surfaces), and a `verdict` — identical | moved | resized | topology-changed, precedence topology-changed > resized > moved > identical. Branch on the verdict; cite the numbers. Optional { render: true } also writes an overlay PNG (added green, removed red, unchanged material as a translucent ghost; the scene is a re-runnable .kcad.ts over lossless BREP sidecars) through the render_preview pipeline and fails open (the numeric diff is still returned) when that pipeline is unavailable. Read-only — never touches the active session.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "baseFile": {
            "type": "string",
            "description": "Baseline script — path to a .kcad.ts file."
          },
          "baseCode": {
            "type": "string",
            "description": "Baseline script — inline source."
          },
          "file": {
            "type": "string",
            "description": "Revised script — path to a .kcad.ts file. Mutually exclusive with params."
          },
          "code": {
            "type": "string",
            "description": "Revised script — inline source. Mutually exclusive with params."
          },
          "params": {
            "type": "object",
            "additionalProperties": true,
            "description": "Param-override mode: re-lower the BASELINE with these declared param() values changed (e.g. { plateThickness: 8 }). Mutually exclusive with file/code. A name the baseline does not declare fails with the declared-param list in the message."
          },
          "render": {
            "type": "boolean",
            "description": "Also render an overlay PNG — added material green, removed material red — via the render_preview pipeline. Off by default; the numeric table is the agent-facing evidence."
          },
          "out_dir": {
            "type": "string",
            "description": "Directory for the overlay PNG, its STL inputs, and the generated overlay script. Default: a temp dir."
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": true
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "base": {
            "type": "object",
            "additionalProperties": true,
            "description": "Baseline summary { featureCount, bodyCount, isAssembly } (success)."
          },
          "revised": {
            "type": "object",
            "additionalProperties": true,
            "description": "Revision summary { featureCount, bodyCount, isAssembly } (success)."
          },
          "bodies": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "baseName": {
                  "type": "string"
                },
                "revisedName": {
                  "type": "string"
                },
                "matchedBy": {
                  "type": "string",
                  "enum": [
                    "name",
                    "position"
                  ],
                  "description": "How this pair was established."
                },
                "verdict": {
                  "type": "string",
                  "enum": [
                    "identical",
                    "moved",
                    "resized",
                    "topology-changed"
                  ],
                  "description": "The field to branch on. Precedence: topology-changed > resized > moved > identical."
                },
                "volumeMm3": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "{ base, revised, delta } in mm³."
                },
                "addedMm3": {
                  "type": "number",
                  "description": "volume(revised − base) — material that appeared."
                },
                "removedMm3": {
                  "type": "number",
                  "description": "volume(base − revised) — material that vanished."
                },
                "commonMm3": {
                  "type": "number",
                  "description": "volume(base ∩ revised) — material that stayed put."
                },
                "bbox": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "Exact bbox both sides plus min/max/extent deltas (mm)."
                },
                "faceCount": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "{ base, revised, delta } BREP face count."
                },
                "edgeCount": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "{ base, revised, delta } BREP edge count."
                },
                "holeCount": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "{ base, revised, delta } cylindrical-hole count."
                },
                "maxDeviationMm": {
                  "type": "number",
                  "description": "Two-sided discrete Hausdorff distance between the two surfaces."
                }
              },
              "required": [
                "name",
                "verdict",
                "addedMm3",
                "removedMm3",
                "commonMm3"
              ],
              "additionalProperties": true
            },
            "description": "Per matched body, the material-level delta (success)."
          },
          "unmatched": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Bodies present on only one side; each also raises diff.body.unmatched."
          },
          "summary": {
            "type": "object",
            "additionalProperties": true,
            "description": "Verdict counts plus totalAddedMm3 / totalRemovedMm3 / maxDeviationMm."
          },
          "render": {
            "type": "object",
            "additionalProperties": true,
            "description": "Overlay result when render: true — { ok, images, out_dir, script_path, error? }."
          },
          "side": {
            "type": "string",
            "description": "Which side failed ('base' | 'revised') (failure)."
          },
          "error": {
            "type": "string",
            "description": "Failure message (failure)."
          },
          "errorCode": {
            "type": "string"
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "drawing_to_cad",
      "description": "Use this when the reference for a part is a 2D engineering drawing PDF (orthographic views with dimensions), not a photo. Deterministic, no vision model: reads the vector linework (stroke width, dash) and positioned text; classifies visible / hidden / center / dimension / extension lines; reads the title block scale, units and projection symbol; identifies front / top / side views by projection alignment (third- or first-angle); ties dimension text to its lines (⌀, R, 4×, ±, THRU, depth). Dimension values win over measured lengths. Rebuilds the part as the view silhouette extruded by the depth an orthogonal view shows, or a turned part revolved from its half-silhouette, plus holes from ⌀ circles with THRU or hidden-line depth. Returns `script` — a `.kcad.ts` with role-named params (width, thickness, holeDia, hole1X, dia1, step1Length …) — and `ledger`, an assumption ledger where stated dimensions are `visible`, symmetry-derived positions `inferred`, defaults `assumed` and an unstated depth `missing`; a dimension that disagrees with the linework keeps its value and records the disagreement as an open fact. With verify (default) the script is evaluated, re-projected through the svg-drawing view stage and compared: `fidelity.verdict` is match | partial | mismatch | failed with per-axis extents, hole diameters and per-view silhouette IoU. Pass `out` to write the script and its `<stem>.ledger.json` (resolve open facts with resolve_assumptions, then set_param). A scanned (raster-only) page fails with reference.drawing.raster-only — use trace_from_image for those.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "path": {
            "type": "string",
            "description": "Path to the drawing PDF on the machine running kernelCAD."
          },
          "pdfBase64": {
            "type": "string",
            "description": "The PDF inline, base64-encoded. Use this instead of `path` against a hosted kernelCAD server."
          },
          "page": {
            "type": "integer",
            "minimum": 1,
            "description": "1-based page to read. Default 1."
          },
          "projection": {
            "type": "string",
            "enum": [
              "third-angle",
              "first-angle"
            ],
            "description": "Override the projection angle read from the sheet (default: projection symbol or note, else third-angle)."
          },
          "out": {
            "type": "string",
            "description": "Write the emitted script here (a .kcad.ts path); the ledger is written beside it as <stem>.ledger.json."
          },
          "verify": {
            "type": "boolean",
            "description": "Evaluate the rebuilt part and compare it with the drawing. Default true."
          }
        }
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": true
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "page": {
            "type": "integer"
          },
          "pageCount": {
            "type": "integer"
          },
          "sheet": {
            "type": "object",
            "additionalProperties": true,
            "description": "{ widthMm, heightMm, scale: { text, sheetPerModel, source }, units, projection } read off the sheet."
          },
          "views": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Identified orthographic views: { name, bboxMm, identifiedBy, label? }."
          },
          "reconstruction": {
            "type": "object",
            "additionalProperties": true,
            "description": "{ kind: extrude | revolve, profileView, axis, holeCount, extents }."
          },
          "params": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Role-named params declared by the script: { name, value, description }."
          },
          "script": {
            "type": "string",
            "description": "The emitted .kcad.ts source."
          },
          "scriptPath": {
            "type": "string",
            "description": "Where the script was written (when `out` was given)."
          },
          "ledger": {
            "type": "object",
            "additionalProperties": true,
            "description": "Assumption ledger: { facts, unresolvedCount }; facts are visible / inferred / assumed / missing, disagreements recorded on the fact."
          },
          "ledgerPath": {
            "type": "string",
            "description": "Where the ledger was written (when `out` was given); pass it to resolve_assumptions."
          },
          "fidelity": {
            "type": "object",
            "additionalProperties": true,
            "description": "{ verdict: match | partial | mismatch | failed, extents, holes, silhouettes, reasons } from evaluating and re-projecting the script."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        },
        "required": [
          "ok",
          "views",
          "params",
          "ledger",
          "diagnostics"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "mesh_to_features",
      "description": "Use this when you are handed an STL, OBJ or 3MF of a mostly prismatic mechanical part (plate, bracket, spacer, flange, housing block) and need an EDITABLE kernelCAD model of it rather than a faceted lib.fromSTL import. Deterministic, measured, self-verifying: it welds and checks the mesh, segments planes and cylinders, picks the extrusion axis, slices each band and fits exact lines / arcs / circles, snaps near-round values (each snap recorded), then emits a readable .kcad.ts with named param()s — a revolve for concentric round stacks, extruded profiles otherwise, .hole()/.holes() for through, blind and counterbored bores (axial and side-drilled), .cutout() for pockets, .fillet() for constant-radius edge blends (radius measured on the sharp edge, edges grouped by radius and picked with the shortest exact edge query), boolean subtractions for what no drilling feature can reach. It then EVALUATES that script and compares it with the mesh: volume IoU (column ray casting) and symmetric surface deviation (max + RMS), over up to 4 refinement passes. Returns { script, ledger, fidelity: { maxDeviationMm, rmsMm, volumeIoU, verdict: faithful | approximate | failed, thresholds }, unmatchedRegions, features, passes }. A fillet or sharp reading is kept by which measures better; variable-radius blends and chamfers are reported, not forced. The verdict is computed from the numbers — faithful needs IoU >= minIoU AND max deviation <= maxDeviationMm AND a watertight mesh AND no unmatched region. Freeform surfaces, tilted planes and side bosses are listed in unmatchedRegions (reference.mesh.freeform-region-unmatched), never silently dropped. The ledger uses fact ids equal to param names, so resolve_assumptions on the written <out>.ledger.json yields paramOverrides for set_param. Pass { out } to write the script and ledger; the mesh itself is never modified.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "file": {
            "type": "string",
            "description": "Path to a .stl (binary or ASCII), .obj or .3mf mesh. One of file / data is required."
          },
          "data": {
            "type": "string",
            "description": "Mesh bytes as base64 — use when the server cannot see your filesystem."
          },
          "format": {
            "type": "string",
            "enum": [
              "stl",
              "obj",
              "3mf"
            ],
            "description": "Format override; default from the extension or the content."
          },
          "out": {
            "type": "string",
            "description": "Write the emitted script to this .kcad.ts path and the assumption ledger to the sibling .ledger.json."
          },
          "minIoU": {
            "type": "number",
            "description": "Volume IoU a faithful verdict requires. Default 0.98."
          },
          "maxDeviationMm": {
            "type": "number",
            "description": "Max surface deviation (mm) a faithful verdict allows. Default max(0.25, 0.1 % of the bbox diagonal)."
          },
          "maxPasses": {
            "type": "number",
            "description": "Refinement passes, 1–4. Default 4; stops early at the first faithful pass."
          },
          "weldToleranceMm": {
            "type": "number",
            "description": "Vertex weld distance in mm. Default max(1e-4, 1e-6 × bbox diagonal)."
          },
          "maxTriangles": {
            "type": "number",
            "description": "Refuse meshes above this triangle count instead of stalling. Default 300000."
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": true
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "script": {
            "type": "string",
            "description": "The emitted, evaluable .kcad.ts source (success)."
          },
          "ledger": {
            "type": "object",
            "additionalProperties": true,
            "description": "AssumptionLedger { facts, unresolvedCount }; dimension fact ids equal the param names (success)."
          },
          "fidelity": {
            "type": "object",
            "properties": {
              "maxDeviationMm": {
                "type": "number",
                "description": "Two-sided discrete Hausdorff distance, mesh vs reconstruction."
              },
              "rmsMm": {
                "type": "number",
                "description": "RMS of the sampled point-to-surface distances."
              },
              "volumeIoU": {
                "type": "number",
                "description": "Volume intersection-over-union by column ray casting."
              },
              "verdict": {
                "type": "string",
                "enum": [
                  "faithful",
                  "approximate",
                  "failed"
                ],
                "description": "faithful = IoU and deviation within thresholds, watertight mesh, nothing unmatched; approximate = IoU >= 0.85."
              },
              "thresholds": {
                "type": "object",
                "additionalProperties": true,
                "description": "{ minIoU, maxDeviationMm, approximateIoU } actually applied."
              },
              "pass": {
                "type": "number",
                "description": "Refinement pass whose script is returned."
              }
            },
            "required": [
              "maxDeviationMm",
              "rmsMm",
              "volumeIoU",
              "verdict"
            ],
            "additionalProperties": true,
            "description": "Measured fidelity of the returned script (success)."
          },
          "unmatchedRegions": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Surface regions no emitted feature represents: { kind, reason, areaMm2, triangleCount, centroid, bbox }."
          },
          "features": {
            "type": "object",
            "additionalProperties": true,
            "description": "Body kind, hole groups, cutouts, boolean remainders, params (success)."
          },
          "mesh": {
            "type": "object",
            "additionalProperties": true,
            "description": "Clean-up and watertightness report for the input mesh."
          },
          "reconstructedHoles": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Holes the B-rep hole detector finds on the reconstruction."
          },
          "passes": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Per-pass tolerances and measured fidelity."
          },
          "notRepresented": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "written": {
            "type": "object",
            "additionalProperties": true,
            "description": "{ script, ledger } paths when out was given."
          },
          "error": {
            "type": "string",
            "description": "Failure message (failure)."
          },
          "errorCode": {
            "type": "string"
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "execute_cookbook",
      "description": "Use this when you need evaluate_script (and optionally open_in_studio) for an industry / cookbook demo in ONE step — after lookup_cookbook for industry demos, prefer execute_cookbook when you need evaluate+Studio together; empty lookup is not a stop (freehand-author instead). Resolves a cookbook snippet by `id` or BM25 `query` (same ranking as lookup_cookbook), evaluates its body via evaluate_script with bounded vendor timeouts, and returns explicit status with stage resolve|evaluate|open_in_studio. Pass openInStudio:true to publish the same script via open_in_studio after a green full evaluate (hosted MCP). dryRun:true is the fast capture-only path — it is NOT evidence the cookbook builds a solid or is safe to publish; finish with dryRun:false (default) before claiming success or opening Studio.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Cookbook snippet id (e.g. gt2-timing-belt-drive, extrude-rounded-rect-plate)."
          },
          "query": {
            "type": "string",
            "description": "When id is omitted: natural-language query; BM25 picks the top hit (same as lookup_cookbook)."
          },
          "openInStudio": {
            "type": "boolean",
            "description": "Default false. When true, after a green full (non-dryRun) evaluate, call open_in_studio on the same script (hosted MCP).",
            "default": false
          },
          "kernel": {
            "type": "string",
            "enum": [
              "occt",
              "smlib"
            ],
            "description": "Solid-modeling kernel forwarded to evaluate_script. Default 'occt'; opt-in 'smlib' uses guarded candidates with explicit OCCT fallback diagnostics."
          },
          "dryRun": {
            "type": "boolean",
            "description": "Default false. dryRun:true is NOT evidence the cookbook builds a solid — capture-only checks; do not claim success or open Studio from a dry run alone.",
            "default": false
          }
        }
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": true
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "cookbookId": {
            "type": "string",
            "description": "Resolved cookbook snippet id."
          },
          "title": {
            "type": "string",
            "description": "Resolved cookbook title."
          },
          "evaluate": {
            "type": "object",
            "additionalProperties": true,
            "description": "Full evaluate_script result (same shape)."
          },
          "openInStudio": {
            "type": "object",
            "additionalProperties": true,
            "description": "open_in_studio result when openInStudio was requested."
          },
          "executionId": {
            "type": "string",
            "description": "Short id for logs / correlation."
          },
          "code": {
            "type": "string",
            "description": "Snippet body used for evaluate / Studio."
          },
          "dryRunNotEvidence": {
            "type": "boolean",
            "description": "Present when dryRun:true — dryRun success is not evidence the solid built."
          },
          "error": {
            "type": "string"
          },
          "stage": {
            "type": "string",
            "description": "'resolve' | 'evaluate' | 'open_in_studio' on failure."
          }
        },
        "required": [
          "ok",
          "executionId"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "get_selection",
      "description": "Use this when you need to read the human/agent selection in a local Studio session. Returns one clicked face or edge (or null), with current-generation mesh-local shapeIndex/kind/id and creating featureId. During a rebuild selection is null with “selection pending rebuild” until Studio uniquely verifies the face; ambiguous or deleted faces are cleared. Inspect the current shape before authoring a fillet. Requires a running local Studio opened on the same script; hosted sessions are not supported.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "studio_url": {
            "type": "string",
            "description": "Local Studio HTTP origin, e.g. http://localhost:5173."
          },
          "session": {
            "type": "string",
            "description": "Studio sessionToken from GET /__kernelcad/session?script=<path>. Use the same script as the viewer."
          }
        },
        "required": [
          "studio_url",
          "session"
        ]
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": true
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "selection": {
            "anyOf": [
              {
                "type": "null"
              },
              {
                "type": "object",
                "additionalProperties": true
              }
            ]
          },
          "revision": {
            "type": "integer"
          },
          "modelGeneration": {
            "type": "integer"
          },
          "error": {
            "type": "string"
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "set_selection",
      "description": "Use this when you need to replace the shared local Studio face/edge selection, or clear it with selection:null. The viewer highlights the pick on its next sync (300 ms). Does not edit geometry. Pass model_generation from get_selection; writes from an older generation are rejected. Use only current shape indices. Requires a local Studio session.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "studio_url": {
            "type": "string",
            "description": "Local Studio HTTP origin, e.g. http://localhost:5173."
          },
          "session": {
            "type": "string",
            "description": "Studio sessionToken from GET /__kernelcad/session?script=<path>. Use the same script as the viewer."
          },
          "model_generation": {
            "type": "integer",
            "minimum": 0,
            "description": "modelGeneration from get_selection; rejects picks from a prior mesh."
          },
          "selection": {
            "anyOf": [
              {
                "type": "null"
              },
              {
                "type": "object",
                "properties": {
                  "shapeIndex": {
                    "type": "integer",
                    "minimum": 0
                  },
                  "kind": {
                    "type": "string",
                    "enum": [
                      "face",
                      "edge"
                    ]
                  },
                  "id": {
                    "type": "integer",
                    "minimum": 0
                  },
                  "featureId": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "minLength": 1
                  }
                },
                "required": [
                  "shapeIndex",
                  "kind",
                  "id",
                  "featureId"
                ],
                "additionalProperties": false
              }
            ]
          }
        },
        "required": [
          "studio_url",
          "session",
          "model_generation",
          "selection"
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": true
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "selection": {
            "anyOf": [
              {
                "type": "null"
              },
              {
                "type": "object",
                "additionalProperties": true
              }
            ]
          },
          "revision": {
            "type": "integer"
          },
          "modelGeneration": {
            "type": "integer"
          },
          "error": {
            "type": "string"
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "import_step",
      "description": "Use this when the user wants to start from their own STEP or STL file (a part they designed elsewhere, a vendor model). Give exactly one source: url (a public https direct-download link), upload (a file the user attached in ChatGPT), or content_base64 (raw bytes, small files only). Max 50 MB. The format is detected from the bytes (or pass format: 'step' | 'stl'). Writes the file and a starter <name>.kcad.ts whose base body is lib.fromSTEP / lib.fromSTL into output_dir (default: a fresh temp dir), evaluates it, and returns { ok, format, model_path, script_path, code, bbox }. Pass script_path as { file } to evaluate_script, add_feature, dfm_review, export and the other tools, or edit code to build on the body. STL is a mesh: booleans, bbox and export work, but faces stay planar facets (use mesh_to_features for an editable feature tree). A non-watertight STL is refused unless allow_open is true.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "description": "Public https URL that downloads the .step/.stp/.stl file directly."
          },
          "upload": {
            "type": "object",
            "description": "ChatGPT file reference for a file the user attached.",
            "properties": {
              "download_url": {
                "type": "string"
              },
              "file_id": {
                "type": "string"
              },
              "mime_type": {
                "type": "string"
              },
              "file_name": {
                "type": "string"
              }
            },
            "required": [
              "download_url",
              "file_id"
            ]
          },
          "content_base64": {
            "type": "string",
            "description": "The file bytes, base64-encoded (small files)."
          },
          "file_name": {
            "type": "string",
            "description": "Original file name, used for format detection."
          },
          "format": {
            "type": "string",
            "enum": [
              "step",
              "stl"
            ],
            "description": "Override format detection."
          },
          "output_dir": {
            "type": "string",
            "description": "Where to write the file and starter script. Default: a new temp directory."
          },
          "name": {
            "type": "string",
            "description": "Base name for the written files. Default 'imported'."
          },
          "allow_open": {
            "type": "boolean",
            "description": "STL only: accept a non-watertight mesh as an open shell.",
            "default": false
          }
        }
      },
      "_meta": {
        "openai/fileParams": [
          "upload"
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": true
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "format": {
            "type": "string",
            "enum": [
              "step",
              "stl"
            ]
          },
          "model_path": {
            "type": "string",
            "description": "The imported file on disk."
          },
          "script_path": {
            "type": "string",
            "description": "Starter .kcad.ts whose base body is the imported file; pass as { file } to other tools."
          },
          "code": {
            "type": "string",
            "description": "Source of the starter script."
          },
          "byte_count": {
            "type": "number"
          },
          "bbox": {
            "type": "object",
            "additionalProperties": true,
            "description": "{ min, max, size } in mm."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "error": {
            "type": "string"
          }
        },
        "required": [
          "ok",
          "diagnostics"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "fab_pack",
      "description": "Use this when the user wants to get a part made: packages the fabrication files into one directory plus a zip, and returns links to public instant-quote pages. Pass { file | code } and output_dir; optional scope ('part', default — one script's files; 'bom' — the whole assembly's BOM: per-part single-body files, per-part drawings, bom.csv/json and vendor handoff texts), name (default 'part'), formats (default step, stl, 3mf, pdf-drawing, bom-csv; add 'dxf' for flat or sheet parts), and processes ('3d-print' | 'cnc' | 'sheet-cut') to filter the links (bom: also narrows which fabricated rows are packed). Each file is written by the export tool, so its gates apply; a format that fails is reported in files[] and the rest still ship. Also writes manifest.json and README.txt. quote_links lists JLC3DP, JLCCNC, PCBWay, Xometry, SendCutSend and Craftcloud with the pack file to upload to each. One body per file: multi-body files are rejected by every shop. DXF is written only for flat or sheet-metal parts. The McMaster handoff text carries part numbers only, because McMaster quantities are packs and pack sizes are not in the catalog yet. These are plain web pages: nothing is uploaded or ordered. The user opens the link and uploads the file. Run dfm_review first if you have not.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "scope": {
            "type": "string",
            "enum": [
              "part",
              "bom"
            ],
            "description": "Default 'part' (a single-part pack). 'bom' packs the whole assembly's BOM: per-part single-body files, per-part drawings, bom.csv/json, vendor handoff texts, and per-process quote links."
          },
          "file": {
            "type": "string",
            "description": "Path to a .kcad.ts script file."
          },
          "code": {
            "type": "string",
            "description": "Inline kernelCAD script source."
          },
          "output_dir": {
            "type": "string",
            "description": "Directory to write the pack into (created if missing)."
          },
          "name": {
            "type": "string",
            "description": "Base file name (letters, digits, '.', '_', '-'). Default 'part'."
          },
          "formats": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "step",
                "stl",
                "3mf",
                "pdf-drawing",
                "bom-csv",
                "dxf"
              ]
            },
            "description": "Files to include. Default step, stl, 3mf, pdf-drawing, bom-csv."
          },
          "processes": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "3d-print",
                "cnc",
                "sheet-cut"
              ]
            },
            "description": "Only return quote links for these processes. Default: all."
          }
        },
        "required": [
          "output_dir"
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": true
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "description": "True when every requested file was exported. bom scope: true when the pack has entries."
          },
          "output_dir": {
            "type": "string"
          },
          "zip_path": {
            "type": "string",
            "description": "Zip holding every written file, manifest.json and README.txt. bom scope: '<name>-order-pack.zip' with the per-part files, BOM, handoffs, manifest and README."
          },
          "files": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "{ format, ok, path?, byte_count?, error? } per requested format. bom scope: one { format: \"order-pack\", ok, path, byte_count, part_files } entry for the zip, part_files listing the per-part entry paths."
          },
          "quote_links": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "{ service, processes, url, accepts, upload_file? }: public instant-quote pages; nothing is uploaded. bom scope: one link per service whose processes intersect the packed rows, upload_file naming an accepted part file when one was written."
          },
          "note": {
            "type": "string",
            "description": "Plain-language summary; bom scope covers the pack contents, the public upload pages, and a note count when the manifest carries notes."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "error": {
            "type": "string"
          }
        },
        "required": [
          "ok",
          "files",
          "quote_links"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "dfm_review",
      "description": "Use this when you need a manufacturability (DFM) report before printing or machining a part: returns a pass/fail checklist, no dfmSpec(...) needed. Pass { file | code } and optional processes (default ['fdm', 'cnc']). FDM 3D printing checks: fdm.overhangs (unsupported overhang steeper than max_overhang_deg, default 45° from vertical), fdm.bridging (bridges over max_bridge_mm, default 10), fdm.min-wall (walls under 2 × nozzle_mm, default 0.4 mm nozzle), fdm.min-hole (holes under 5 × nozzle), fdm.min-pin (warn), fdm.bed-fit (printer profile bed, default generic-fdm), fdm.bed-contact (warn). CNC 3-axis milling checks: cnc.undercuts (surface unreachable from approach_axes, default ['+z']; list several axes for several setups) and cnc.internal-corner-radius (sharp internal corners and fillets smaller than the end-mill radius, tool_diameter_mm default 6). Returns { ok, verdict: 'pass'|'fail', checks: [{ id, process, part, status: 'pass'|'fail'|'warn', summary, value?, limit? }], fdm?, cnc?, diagnostics }. Settings from the script's dfmSpec({ process: 'fdm' }) are used as defaults; call options win. For the script-declared gates (clearance, voids, channels) use verify({ check: 'dfm' }).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "file": {
            "type": "string",
            "description": "Path to a .kcad.ts script file."
          },
          "code": {
            "type": "string",
            "description": "Inline kernelCAD script source."
          },
          "processes": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "fdm",
                "cnc"
              ]
            },
            "description": "Processes to review. Default ['fdm', 'cnc']."
          },
          "nozzle_mm": {
            "type": "number",
            "description": "FDM nozzle diameter, mm. Default 0.4."
          },
          "max_overhang_deg": {
            "type": "number",
            "description": "FDM steepest printable overhang, degrees from vertical (0 = wall, 90 = flat ceiling). Default 45."
          },
          "max_bridge_mm": {
            "type": "number",
            "description": "FDM longest unsupported bridge, mm. Default 10."
          },
          "printer": {
            "type": "string",
            "enum": [
              "generic-fdm",
              "bambu-a1-mini",
              "bambu-a1",
              "bambu-p1s",
              "bambu-p1p",
              "bambu-x1c",
              "bambu-x1e",
              "bambu-h2d",
              "bambu-h2s",
              "prusa-mini-plus",
              "prusa-mk4s",
              "prusa-core-one",
              "prusa-xl",
              "creality-ender-3-v3",
              "creality-k1",
              "creality-k1-max",
              "creality-k2-plus",
              "elegoo-neptune-4-pro",
              "anycubic-kobra-3",
              "voron-2.4-250",
              "voron-2.4-300",
              "voron-2.4-350",
              "ultimaker-s5"
            ],
            "description": "FDM printer profile id for the bed-fit check. Default 'generic-fdm'."
          },
          "build_direction": {
            "type": "string",
            "enum": [
              "+x",
              "-x",
              "+y",
              "-y",
              "+z",
              "-z"
            ],
            "description": "FDM part-local axis pointing up from the bed. Default '+z'."
          },
          "tool_diameter_mm": {
            "type": "number",
            "description": "CNC end-mill diameter, mm. Default 6."
          },
          "approach_axes": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "+x",
                "-x",
                "+y",
                "-y",
                "+z",
                "-z"
              ]
            },
            "description": "CNC tool approach directions, one per setup (the tool comes from that side). Default ['+z']."
          },
          "max_undercut_area_mm2": {
            "type": "number",
            "description": "CNC unreachable area tolerated before cnc.undercuts fails, mm². Default 1."
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "verdict": {
            "type": "string",
            "enum": [
              "pass",
              "fail"
            ],
            "description": "'fail' when any check fails; warnings do not fail the review."
          },
          "processes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "checks": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Pass/fail checklist: { id (fdm.overhangs | fdm.bridging | fdm.min-wall | fdm.min-hole | fdm.min-pin | fdm.bed-fit | fdm.bed-contact | cnc.undercuts | cnc.internal-corner-radius), process, part, status: 'pass'|'fail'|'warn', summary, value?, limit? }."
          },
          "fdm": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Per-part FDM engine report (part-local coordinates)."
          },
          "cnc": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Per-part CNC engine report (part-local coordinates)."
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        },
        "required": [
          "ok",
          "verdict",
          "checks",
          "diagnostics"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "ray_pick",
      "description": "Use this when you need the faces a ray hits in a local Studio model, nearest first, with points, distances, and normals. Inputs are model units (mm); direction is normalized. Requires the local Studio URL and session token for the same script, reads the current model generation, and returns a set_selection argument object with every hit. feature_id must identify a displayed terminal shape; intermediates have no current viewer shapeIndex. Intersections use the viewer per-face tessellation, so curved-surface points and normals are mesh approximations.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "file": {
            "type": "string",
            "description": "Path to a .kcad.ts script."
          },
          "code": {
            "type": "string",
            "description": "Inline kernelCAD script source."
          },
          "feature_id": {
            "type": "string",
            "description": "Displayed terminal feature to ray-pick; defaults to the returned feature. Intermediate features are not available as current viewer selections."
          },
          "studio_url": {
            "type": "string",
            "description": "Local Studio HTTP origin, e.g. http://localhost:5173."
          },
          "session": {
            "type": "string",
            "minLength": 1,
            "description": "Studio sessionToken for this script, from GET /__kernelcad/session?script=<path>."
          },
          "origin": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "minItems": 3,
            "maxItems": 3,
            "description": "Ray origin [x, y, z] in model units."
          },
          "direction": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "minItems": 3,
            "maxItems": 3,
            "description": "Nonzero ray direction [x, y, z]; normalized internally."
          }
        },
        "required": [
          "origin",
          "direction",
          "studio_url",
          "session"
        ],
        "allOf": [
          {
            "oneOf": [
              {
                "required": [
                  "file"
                ],
                "not": {
                  "required": [
                    "code"
                  ]
                }
              },
              {
                "required": [
                  "code"
                ],
                "not": {
                  "required": [
                    "file"
                  ]
                }
              }
            ]
          }
        ]
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "feature_id": {
            "type": "string"
          },
          "shape_index": {
            "type": "integer"
          },
          "studio_url": {
            "type": "string"
          },
          "session": {
            "type": "string"
          },
          "model_generation": {
            "type": "integer"
          },
          "hit_basis": {
            "type": "string",
            "enum": [
              "per-face tessellation"
            ]
          },
          "hits": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true,
              "description": "face_id, point, distance, normal, model_generation, selection, and set_selection arguments ready to pass directly to set_selection."
            }
          },
          "error": {
            "type": "string"
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "inspect_nurbs",
      "description": "Evaluate supplied kernelCAD code or a file to capture an authored NURBS curve (nurbsCurve/spline3d). Returns degree, distinct knots and multiplicities, poles, weights, rational and uniformWeights flags, hasNonUnitWeights, and parameter range. Defaults to the last captured curve in that script; pass feature_id to choose one. The source may load referenced assets. Reports authored curve data, not exact geometry-derived B-rep edge/face NURBS; surface extraction and blending are not supported. Does not update the active MCP session or write a project.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "file": {
            "type": "string",
            "description": "Path to a .kcad.ts script file."
          },
          "code": {
            "type": "string",
            "description": "Inline kernelCAD script source."
          },
          "feature_id": {
            "type": "string",
            "description": "Optional curve3d FeatureId; defaults to the last captured NURBS curve."
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": true
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "feature_id": {
            "type": "string"
          },
          "entity": {
            "type": "string",
            "enum": [
              "curve"
            ]
          },
          "representation": {
            "type": "string"
          },
          "degree": {
            "type": "integer"
          },
          "knots": {
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "multiplicities": {
            "type": "array",
            "items": {
              "type": "integer"
            }
          },
          "poles": {
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "type": "number"
              }
            }
          },
          "weights": {
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "rational": {
            "type": "boolean",
            "description": "OCCT IsRational semantics: true when weights are not all equal. Equal non-unit weights cancel uniformly and are reported as non-rational."
          },
          "uniformWeights": {
            "type": "boolean",
            "description": "True when all weights have the same value, including equal weights other than 1."
          },
          "hasNonUnitWeights": {
            "type": "boolean",
            "description": "True when any weight differs from 1, even if all weights are equal and rational is false."
          },
          "parameter_range": {
            "type": "array",
            "items": {
              "type": "number"
            }
          },
          "closed": {
            "type": "boolean"
          },
          "limitations": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "error": {
            "type": "string"
          },
          "errorCode": {
            "type": "string"
          },
          "hint": {
            "type": "string"
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "fit_plane",
      "description": "Use this when you need to fit an orthogonal least-squares plane to XYZ point-cloud data. Returns centroid, deterministic unit normal, signed point residuals, RMS residual and maximum absolute residual. Accepts points already parsed by the caller from scan data or mesh vertices. Computes parameters only; it does not create a surface body. Requires at least three non-collinear finite points.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "points": {
            "type": "array",
            "minItems": 3,
            "maxItems": 100000,
            "items": {
              "type": "array",
              "minItems": 3,
              "maxItems": 3,
              "items": {
                "type": "number"
              }
            },
            "description": "Point cloud as [x, y, z] coordinate triples in model units."
          }
        },
        "required": [
          "points"
        ]
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "description": "Present and true when a plane fit succeeds; false when input validation or fitting fails."
          },
          "centroid": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "description": "Least-squares plane centroid [x, y, z]."
          },
          "normal": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "description": "Deterministic unit plane normal [x, y, z]."
          },
          "residuals": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "description": "Signed orthogonal distances in input order."
          },
          "rms": {
            "type": "number",
            "description": "Root mean square orthogonal residual."
          },
          "maxAbsResidual": {
            "type": "number",
            "description": "Maximum absolute orthogonal residual."
          },
          "error": {
            "type": "string",
            "description": "Failure message; present when ok is false."
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "mesh_boolean",
      "description": "Use this when the user wants to union, subtract, or intersect two imported triangle mesh solids (STL, OBJ, or 3MF). Supports union, subtract (A minus B) and intersect. Pass each operand as { file } on the MCP server or { data } with base64 mesh bytes; formats are detected or may be specified. Returns volume in mm³, triangle count and a binary STL as data_base64; pass that payload to import_step to continue modeling. Inputs must be closed, consistently oriented 2-manifold meshes. Open, non-manifold, or invalid meshes return an error. This computes mesh geometry and does not create an editable B-rep feature tree.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "operation": {
            "type": "string",
            "enum": [
              "union",
              "subtract",
              "intersect"
            ]
          },
          "a": {
            "type": "object",
            "description": "First mesh: { file } or { data } base64, optional format stl|obj|3mf."
          },
          "b": {
            "type": "object",
            "description": "Second mesh: { file } or { data } base64, optional format stl|obj|3mf."
          },
          "toleranceMm": {
            "type": "number",
            "description": "Vertex weld tolerance in mm. Default 0.000001."
          },
          "maxTriangles": {
            "type": "integer",
            "description": "Maximum triangles per input and output. Default and maximum 100000."
          }
        },
        "required": [
          "operation",
          "a",
          "b"
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "operation": {
            "type": "string",
            "enum": [
              "union",
              "subtract",
              "intersect"
            ]
          },
          "volumeMm3": {
            "type": "number",
            "description": "Output mesh volume in cubic millimetres."
          },
          "triangleCount": {
            "type": "number"
          },
          "format": {
            "type": "string",
            "enum": [
              "stl"
            ]
          },
          "data_base64": {
            "type": "string",
            "description": "Binary STL payload; can be passed to import_step as content_base64."
          },
          "error": {
            "type": "string"
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "explode_view",
      "description": "Use this when you need an ordered exploded-view plan for an assembly. Supply parts as {name,center:[x,y,z],size:[x,y,z]} in mm. Optional assembly_order sets the sequence; missing order falls back to input part order, and unlisted/unknown order refs are reported. Choose mode axis (default) or radial; axis follows the requested direction, radial moves parts away from the assembly centroid. The result includes ready-to-paste param_declarations, animation_tracks and reverse_animation_tracks for animationView(), part_transforms for existing shapes, and script_fragment. cameraPlan gives framing guidance.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "parts": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "center": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  },
                  "minItems": 3,
                  "maxItems": 3
                },
                "size": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  },
                  "minItems": 3,
                  "maxItems": 3
                }
              },
              "required": [
                "name",
                "center",
                "size"
              ],
              "additionalProperties": false
            },
            "description": "Named assembly parts and measured bbox centers/sizes in mm."
          },
          "assembly_order": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "mode": {
            "type": "string",
            "enum": [
              "axis",
              "radial"
            ],
            "description": "Explode direction strategy; default axis."
          },
          "axis": {
            "type": "array",
            "items": {
              "type": "number"
            },
            "minItems": 3,
            "maxItems": 3,
            "description": "Assembly direction; default +Z."
          },
          "spacing": {
            "type": "number",
            "description": "Positive spacing scale; default 1.25."
          },
          "duration_ms": {
            "type": "integer",
            "description": "Timeline duration from 500 to 60000 ms; default 3000."
          }
        }
      },
      "annotations": {
        "readOnlyHint": true,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "order": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "durationMs": {
            "type": "number"
          },
          "tracks": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "reverseTracks": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "param_declarations": {
            "type": "string",
            "description": "Ready-to-paste param() calls that declare every animation track parameter with its initial value."
          },
          "script_fragment": {
            "type": "string",
            "description": "Ready-to-paste declarations and forward animationView() call."
          },
          "animation_tracks": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "reverse_animation_tracks": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "part_transforms": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            },
            "description": "Per-part expressions to apply to existing shapes before assembly.part()."
          },
          "cameraPlan": {
            "type": "object",
            "additionalProperties": true,
            "description": "Suggested target and camera distance for assembled/exploded capture framing; camera keyframes are guidance and are not consumed by animationView."
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "playback": {
            "type": "string"
          }
        },
        "required": [
          "ok",
          "order",
          "durationMs",
          "tracks",
          "reverseTracks",
          "warnings",
          "cameraPlan"
        ],
        "additionalProperties": false
      }
    },
    {
      "name": "apply_surface_blend",
      "description": "Use this when you need to author and evaluate a fillet or chamfer on a kernelCAD Shape. Inserts Shape.fillet(radius, selector, { continuity: G1|G2 }) or Shape.chamfer(distance, selector) through the existing public API and returns the patched source plus evaluation diagnostics. Selectors accept EdgeSelector syntax, including canonical edge refs/query strings or { face: canonical name, face label, or face query }. G2 continuity applies to fillets; chamfer uses the existing chamfer API. This authors the operation and does not extract blend-surface NURBS poles; that still requires kernel surface extraction.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Inline .kcad.ts source."
          },
          "shape_binding": {
            "type": "string",
            "description": "Existing Shape variable name to blend."
          },
          "operation": {
            "type": "string",
            "enum": [
              "fillet",
              "chamfer"
            ],
            "description": "Operation; defaults to 'fillet'."
          },
          "radius": {
            "type": "number",
            "exclusiveMinimum": 0,
            "description": "Fillet radius in mm; required for operation:'fillet'."
          },
          "distance": {
            "type": "number",
            "exclusiveMinimum": 0,
            "description": "Chamfer distance in mm; required for operation:'chamfer'."
          },
          "selector": {
            "description": "Optional EdgeSelector: a canonical @kc[...] edge ref/query string or { face: canonical face name, face label, or FaceQuery descriptor }. Omit to select all sharp edges.",
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "object",
                "properties": {
                  "face": {
                    "type": "string"
                  }
                },
                "required": [
                  "face"
                ],
                "additionalProperties": false
              }
            ]
          },
          "continuity": {
            "type": "string",
            "enum": [
              "G1",
              "G2"
            ],
            "description": "Fillet continuity passed to the existing public API; defaults to G1. Chamfer ignores this field."
          }
        },
        "required": [
          "code",
          "shape_binding"
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "new_code": {
            "type": "string"
          },
          "operation": {
            "type": "string",
            "enum": [
              "fillet",
              "chamfer"
            ]
          },
          "selector": {
            "description": "Selector supplied for the authored blend, when present."
          },
          "step": {
            "type": "object",
            "additionalProperties": true
          },
          "sceneSummary": {
            "type": "object",
            "properties": {
              "valid": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "BREP validity, independent of DFM/mechanism/tool success; null if unchecked."
              },
              "volume": {
                "type": [
                  "number",
                  "null"
                ],
                "description": "Volume in mm³; assembly parts summed, including overlaps."
              },
              "faceCount": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "BREP faces, summed per assembly part; not mesh triangles."
              },
              "size": {
                "type": [
                  "array",
                  "null"
                ],
                "items": {
                  "type": "number"
                },
                "minItems": 3,
                "maxItems": 3,
                "description": "Conservative world AABB size [x,y,z] in mm."
              }
            },
            "required": [
              "valid",
              "volume",
              "faceCount",
              "size"
            ],
            "additionalProperties": false
          },
          "diagnostics": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "error": {
            "type": "string"
          }
        },
        "required": [
          "ok"
        ],
        "additionalProperties": true
      }
    },
    {
      "name": "write_bom",
      "description": "Merge a supplied handoff BOM with optional KernelCAD catalog parts, MPNs and pricing, then write a local CSV and return Sheets-ready rows. Pass exactly one of handoff, handoff_json or handoff_path. The default output is a new file under artifacts/bom; an explicit output_path selects another allowed destination. Existing files are preserved unless overwrite:true, which replaces the destination. This tool makes no Google API calls.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "handoff": {
            "type": "object",
            "description": "Handoff object with a parts array."
          },
          "handoff_json": {
            "type": "string",
            "description": "Handoff JSON text."
          },
          "handoff_path": {
            "type": "string",
            "description": "Path to handoff JSON."
          },
          "catalog_parts": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Optional matching KernelCAD catalog entries with id/ref, partNumber, vendor and price."
          },
          "output_path": {
            "type": "string",
            "description": "Optional CSV destination. Defaults to artifacts/bom/bom-<id>.csv."
          },
          "overwrite": {
            "type": "boolean",
            "description": "Set true to replace an existing CSV destination. Existing files are otherwise preserved."
          }
        }
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": true,
        "openWorldHint": true
      }
    },
    {
      "name": "blockout_assembly",
      "description": "Use this when you have a list of parts with bounding boxes and positions (from a layout, spreadsheet, another tool or a sketch) and need an evaluable placeholder assembly script. Pass parts as { name, bboxMm:[x,y,z], positionMm:[x,y,z], rotationDeg?, anchors? } in mm; positionMm locates the bbox lower corner and anchors are named points in assembly coordinates. Optional connections [{ from, to }] reference anchors as \"part.anchor\" (including built-ins origin, bbox_center, bbox_x_min..bbox_z_max) and become fastened mates that express connectivity intent only; no wire or route geometry is generated. Returns the script (corner-anchored box solids with named connectors) plus warnings. It reads no files and cuts nothing; refine the solids with add_part/add_feature afterwards.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Assembly name, default \"blockout\"."
          },
          "parts": {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "bboxMm": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  },
                  "minItems": 3,
                  "maxItems": 3,
                  "description": "Box dimensions [x,y,z] in mm."
                },
                "positionMm": {
                  "type": "array",
                  "items": {
                    "type": "number"
                  },
                  "minItems": 3,
                  "maxItems": 3,
                  "description": "Bbox lower corner in assembly coordinates, mm."
                },
                "rotationDeg": {
                  "description": "Rotation about Z as a number, or XYZ Euler degrees as [x,y,z].",
                  "anyOf": [
                    {
                      "type": "number"
                    },
                    {
                      "type": "array",
                      "items": {
                        "type": "number"
                      },
                      "minItems": 3,
                      "maxItems": 3
                    }
                  ]
                },
                "anchors": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "positionMm": {
                        "type": "array",
                        "items": {
                          "type": "number"
                        },
                        "minItems": 3,
                        "maxItems": 3,
                        "description": "Anchor point in assembly coordinates, mm."
                      }
                    },
                    "required": [
                      "name",
                      "positionMm"
                    ],
                    "additionalProperties": false
                  }
                }
              },
              "required": [
                "name",
                "bboxMm",
                "positionMm"
              ],
              "additionalProperties": false
            }
          },
          "connections": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "from": {
                  "type": "string",
                  "description": "\"part.anchor\""
                },
                "to": {
                  "type": "string",
                  "description": "\"part.anchor\""
                }
              },
              "required": [
                "from",
                "to"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "parts"
        ]
      },
      "annotations": {
        "readOnlyHint": false,
        "destructiveHint": false,
        "openWorldHint": false
      },
      "outputSchema": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "part_count": {
            "type": "number"
          },
          "connection_count": {
            "type": "number"
          },
          "script": {
            "type": "string",
            "description": "Evaluable .kcad.ts assembly script with bbox placeholder parts and named anchors."
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "error": {
            "type": "string"
          }
        },
        "required": [
          "ok",
          "warnings"
        ],
        "additionalProperties": true
      }
    }
  ]
}
