@vcad/mcp 0.9.4-main.38 → 0.9.4-main.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,4 +6,4 @@ vcad's MCP server as a self-contained bundle (server + BRep kernel WASM).
6
6
  { "mcpServers": { "vcad": { "command": "npx", "args": ["-y", "@vcad/mcp"] } } }
7
7
  ```
8
8
 
9
- Built from 254d4e9d13825ac74a895590703959d77898e1f3 at 2026-07-26T13:42:07.736Z. Source: https://github.com/ecto/vcad
9
+ Built from 6cac4f4f2c7c80a9122ee16857ec2b49f2dcd1f4 at 2026-07-26T14:38:17.346Z. Source: https://github.com/ecto/vcad
package/index.mjs CHANGED
@@ -165,6 +165,7 @@ __export(vcad_kernel_wasm_exports, {
165
165
  estimate_cost_for_process: () => estimate_cost_for_process,
166
166
  eulerXyzDegToQuat: () => eulerXyzDegToQuat,
167
167
  evalVcadSource: () => evalVcadSource,
168
+ evalVcadSourceParametric: () => evalVcadSourceParametric,
168
169
  evalVcadSourceWithModules: () => evalVcadSourceWithModules,
169
170
  evaluateDocument: () => evaluateDocument,
170
171
  evaluateSheetMetalChain: () => evaluateSheetMetalChain,
@@ -177,6 +178,7 @@ __export(vcad_kernel_wasm_exports, {
177
178
  exprEvaluate: () => exprEvaluate,
178
179
  exprParse: () => exprParse,
179
180
  feaAnalyzeMesh: () => feaAnalyzeMesh,
181
+ feaCheckBeam: () => feaCheckBeam,
180
182
  generate3mf: () => generate3mf,
181
183
  generate3mfWithGcode: () => generate3mfWithGcode,
182
184
  generateGcode: () => generateGcode,
@@ -1776,6 +1778,17 @@ function evalVcadSource(source) {
1776
1778
  }
1777
1779
  return takeFromExternrefTable0(ret[0]);
1778
1780
  }
1781
+ function evalVcadSourceParametric(source, modules_json) {
1782
+ const ptr0 = passStringToWasm0(source, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1783
+ const len0 = WASM_VECTOR_LEN;
1784
+ var ptr1 = isLikeNone(modules_json) ? 0 : passStringToWasm0(modules_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1785
+ var len1 = WASM_VECTOR_LEN;
1786
+ const ret = wasm.evalVcadSourceParametric(ptr0, len0, ptr1, len1);
1787
+ if (ret[2]) {
1788
+ throw takeFromExternrefTable0(ret[1]);
1789
+ }
1790
+ return takeFromExternrefTable0(ret[0]);
1791
+ }
1779
1792
  function evalVcadSourceWithModules(source, modules_json) {
1780
1793
  const ptr0 = passStringToWasm0(source, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1781
1794
  const len0 = WASM_VECTOR_LEN;
@@ -1925,6 +1938,15 @@ function feaAnalyzeMesh(spec_json, options_json, positions, indices) {
1925
1938
  }
1926
1939
  return takeFromExternrefTable0(ret[0]);
1927
1940
  }
1941
+ function feaCheckBeam(case_json) {
1942
+ const ptr0 = passStringToWasm0(case_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1943
+ const len0 = WASM_VECTOR_LEN;
1944
+ const ret = wasm.feaCheckBeam(ptr0, len0);
1945
+ if (ret[2]) {
1946
+ throw takeFromExternrefTable0(ret[1]);
1947
+ }
1948
+ return takeFromExternrefTable0(ret[0]);
1949
+ }
1928
1950
  function generate3mf(name, vertices, indices, settings_json) {
1929
1951
  const ptr0 = passStringToWasm0(name, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
1930
1952
  const len0 = WASM_VECTOR_LEN;
@@ -11516,6 +11538,7 @@ var init_dist = __esm({
11516
11538
  WasmAnnotationLayer: wasmModule7.WasmAnnotationLayer,
11517
11539
  projectMesh: wasmModule7.projectMesh,
11518
11540
  importStepBuffer: wasmModule7.importStepBuffer,
11541
+ documentToStepBuffer: wasmModule7.documentToStepBuffer,
11519
11542
  importUrdfBuffer: wasmModule7.importUrdfBuffer,
11520
11543
  exportProjectedViewToDxf: wasmModule7.exportProjectedViewToDxf,
11521
11544
  offsetSectionMesh: wasmModule7.offsetSectionMesh,
@@ -11526,6 +11549,7 @@ var init_dist = __esm({
11526
11549
  evaluateDocument: wasmModule7.evaluateDocument,
11527
11550
  evalVcadSource: wasmModule7.evalVcadSource,
11528
11551
  evalVcadSourceWithModules: wasmModule7.evalVcadSourceWithModules,
11552
+ evalVcadSourceParametric: wasmModule7.evalVcadSourceParametric,
11529
11553
  documentParameterGradient: wasmModule7.documentParameterGradient,
11530
11554
  getPartsManifest: wasmModule7.getPartsManifest,
11531
11555
  buildPart: wasmModule7.buildPart,
@@ -12191,6 +12215,19 @@ var init_dist = __esm({
12191
12215
  return null;
12192
12216
  return foldedSheetMetalStep(chain, this.kernel);
12193
12217
  }
12218
+ /**
12219
+ * Export the document's scene roots to a STEP AP214 buffer, preserving
12220
+ * BRep through booleans, transforms, fillets, and sweeps — one STEP body
12221
+ * per visible root. Throws when a root evaluated to mesh-only geometry
12222
+ * (the kernel error names the offending roots) or when the loaded WASM
12223
+ * kernel predates the binding.
12224
+ */
12225
+ documentStep(doc) {
12226
+ if (!this.kernel.documentToStepBuffer) {
12227
+ throw new Error("documentToStepBuffer is not available in this kernel build \u2014 rebuild the WASM kernel");
12228
+ }
12229
+ return this.kernel.documentToStepBuffer(JSON.stringify(doc));
12230
+ }
12194
12231
  /** Create a detail view (magnified region) from a projected view.
12195
12232
  *
12196
12233
  * @param view - The parent projected view
@@ -12230,6 +12267,22 @@ var init_dist = __esm({
12230
12267
  const json = this.kernel.evalVcadSourceWithModules(source, JSON.stringify(modules));
12231
12268
  return JSON.parse(json);
12232
12269
  }
12270
+ /**
12271
+ * Evaluate loon source, returning the document alongside any parametric
12272
+ * warnings — intent the bridge could *not* preserve, such as a declared
12273
+ * parameter that ends up driving no geometry, or a field whose dependence
12274
+ * on a parameter is not affine and so keeps its literal.
12275
+ *
12276
+ * The document is identical to {@link evalVcadSourceWithModules}; only the
12277
+ * authoring feedback is extra. Returns null on kernels predating the
12278
+ * parametric loon forms, so callers can fall back.
12279
+ */
12280
+ evalVcadSourceParametric(source, modules = {}) {
12281
+ if (!this.kernel.evalVcadSourceParametric)
12282
+ return null;
12283
+ const json = this.kernel.evalVcadSourceParametric(source, Object.keys(modules).length ? JSON.stringify(modules) : void 0);
12284
+ return JSON.parse(json);
12285
+ }
12233
12286
  /** Evaluate a preview extrusion without adding to document */
12234
12287
  evaluateExtrudePreview(origin, xDir, yDir, segments, direction) {
12235
12288
  if (segments.length === 0)
@@ -40950,6 +41003,23 @@ var init_CHANGELOG = __esm({
40950
41003
  "verify_receipt"
40951
41004
  ]
40952
41005
  },
41006
+ {
41007
+ id: "2026-07-26-step-export-booleans",
41008
+ version: "0.9.4",
41009
+ date: "2026-07-26",
41010
+ category: "feat",
41011
+ title: "STEP export works on real parts, booleans included",
41012
+ summary: "STEP AP214 export now serializes the evaluated BRep \u2014 booleans, transforms, fillets, and sweeps keep analytic faces \u2014 with one named body per part; mesh-only parts are refused by name.",
41013
+ features: [
41014
+ "step",
41015
+ "export",
41016
+ "booleans",
41017
+ "cnc"
41018
+ ],
41019
+ mcpTools: [
41020
+ "export_cad"
41021
+ ]
41022
+ },
40953
41023
  {
40954
41024
  id: "2026-07-26-render-loon-directly",
40955
41025
  version: "0.9.4",
@@ -40963,6 +41033,40 @@ var init_CHANGELOG = __esm({
40963
41033
  "rendering"
40964
41034
  ]
40965
41035
  },
41036
+ {
41037
+ id: "2026-07-26-photoreal-path-tracer",
41038
+ version: "0.9.4",
41039
+ date: "2026-07-26",
41040
+ category: "feat",
41041
+ title: "Photorealistic rendering with --photoreal",
41042
+ summary: "vcad-render gains a physically-based path tracer: GGX materials with clearcoat, studio softbox lighting, global illumination, and a real camera lens with depth of field.",
41043
+ features: [
41044
+ "rendering",
41045
+ "raytracing",
41046
+ "cli",
41047
+ "materials"
41048
+ ]
41049
+ },
41050
+ {
41051
+ id: "2026-07-26-parametric-loon-datums",
41052
+ version: "0.9.4",
41053
+ date: "2026-07-26",
41054
+ category: "feat",
41055
+ title: "Named parameters, datums and stacks in loon",
41056
+ summary: "Values named with [defparam] survive into the document and are settable with set_parameters; [datum-plane]/[stack] make shared planes and packing clearances named entities instead of repeated literals.",
41057
+ features: [
41058
+ "loon",
41059
+ "parameters",
41060
+ "datums",
41061
+ "assemblies"
41062
+ ],
41063
+ mcpTools: [
41064
+ "create_cad_loon",
41065
+ "list_parameters",
41066
+ "set_parameters",
41067
+ "parameter_gradient"
41068
+ ]
41069
+ },
40966
41070
  {
40967
41071
  id: "2026-07-26-loon-mirror-symmetry",
40968
41072
  version: "0.9.4",
@@ -48729,9 +48833,45 @@ function createCadLoon(input, engine) {
48729
48833
  return { content: [{ type: "text", text: text2 }] };
48730
48834
  }
48731
48835
  const text = format === "json" ? JSON.stringify(doc, null, 2) : toVCode2(doc);
48732
- return {
48733
- content: [{ type: "text", text }]
48734
- };
48836
+ const content = [{ type: "text", text }];
48837
+ const note = parametricNote(source, modules, engine, doc);
48838
+ if (note) content.push({ type: "text", text: note });
48839
+ return { content };
48840
+ }
48841
+ function parametricNote(source, modules, engine, doc) {
48842
+ const names = Object.keys(doc.parameters ?? {}).sort();
48843
+ if (!names.length) return null;
48844
+ const lines = [];
48845
+ const value = (n) => doc.parameters[n].value;
48846
+ const bound = new Set(
48847
+ Object.values(doc.bindings ?? {}).flatMap(
48848
+ (expr) => typeof expr === "string" ? expr.match(/[A-Za-z_]\w*/g) ?? [] : []
48849
+ )
48850
+ );
48851
+ const base = names.filter((n) => typeof value(n) === "number");
48852
+ const derived = names.filter((n) => typeof value(n) === "string");
48853
+ if (base.length) {
48854
+ lines.push(
48855
+ `Parameters (${base.length}, settable): ${base.map((n) => bound.has(n) ? n : `${n} (drives nothing)`).join(", ")}`
48856
+ );
48857
+ }
48858
+ if (derived.length) {
48859
+ lines.push(
48860
+ `Derived (${derived.length}, follow from the above): ${derived.map((n) => `${n} = "${value(n)}"`).join(", ")}`
48861
+ );
48862
+ }
48863
+ const datums = Object.keys(doc.datums ?? {}).sort();
48864
+ if (datums.length) lines.push(`Datums (${datums.length}): ${datums.join(", ")}`);
48865
+ if (base.length) {
48866
+ lines.push("Change any settable parameter with set_parameters \u2014 no re-authoring needed.");
48867
+ }
48868
+ let warnings = [];
48869
+ try {
48870
+ warnings = engine.evalVcadSourceParametric(source, modules)?.warnings ?? [];
48871
+ } catch {
48872
+ }
48873
+ for (const w of warnings) lines.push(`- ${w}`);
48874
+ return lines.join("\n");
48735
48875
  }
48736
48876
  var createCadLoonSchema, toolDefs2;
48737
48877
  var init_loon = __esm({
@@ -48793,7 +48933,7 @@ var init_loon = __esm({
48793
48933
  {
48794
48934
  name: "create_cad_loon",
48795
48935
  pack: null,
48796
- description: 'The preferred authoring tool for whole parts and multi-feature models \u2014 one call, full vocabulary. Create a CAD document from loon source code. Loon is a Lisp-like language for parametric CAD \u2014 the FULL modeling vocabulary (patterns, sketches, extrude/revolve/sweep/loft, assemblies) is available here even where no dedicated MCP tool exists. For incremental single-node edits to an open session, use create/update/delete instead.\n\nPrimitives: [cube x y z], [cylinder r h], [sphere r], [cone r-bottom r-top h], [torus major-r minor-r], [wedge x y z], [prism sides radius height]\nBooleans (subject-last): [difference tool subject], [union other subject], [intersection other subject]\nTransforms (subject-last): [translate x y z s], [rotate rx ry rz s], [scale sx sy sz s], [mirror ox oy oz nx ny nz s] (plane through the origin point with that normal) \u2014 plus the axis sugar [mirror-x s] / [mirror-y s] / [mirror-z s], which mirror through the origin, negating that one coordinate. NEVER hand-mirror by negating coordinates; use these.\nFeatures: [fillet r s], [chamfer d s], [shell t s]\nPatterns (subject-last): [linear-pattern dx dy dz count spacing s], [circular-pattern ox oy oz ax ay az count angle s] \u2014 e.g. a bolt circle is [circular-pattern 0 0 0 0 0 1 6 360 bolt-hole]\nSymmetric patterns (subject-last): [mirror-pattern nx ny nz s] and its sugar [mirror-pattern-x s] / -y / -z union a solid with its mirror image (a left/right pair in one expression, so the halves can\'t drift apart); [quad-pattern s] is the 4-fold X-and-Y version \u2014 a quadruped\'s legs, a 4-post frame, a vehicle chassis\nSketches: [sketch ox oy oz xx xy xz yx yy yz #[segments]] with [line x1 y1 x2 y2] and [arc x1 y1 x2 y2 cx cy ccw]\nSketch ops (sketch-last): [extrude dx dy dz sk], [revolve aox aoy aoz adx ady adz angle sk], [sweep-line sx sy sz ex ey ez sk], [sweep-helix radius pitch height turns sk], [loft #[sk1 sk2 \u2026]], [loft-closed #[sk1 sk2 \u2026]]\nAssemblies: [assembly #[parts] #[instances] #[joints] ground-id] with [part name solid "material"], [instance name part-name x y z], [revolute-joint \u2026], [prismatic-joint \u2026], [fixed-joint \u2026], [ball-joint \u2026]\nAssembly symmetry: author ONE side as an assembly, then [mirror-group-x "-r" side] (or -y / -z) returns it plus a mirrored, suffixed copy \u2014 parts reflected, placements and joint anchors mirrored, and joint axes flipped by the correct rule (a hinge across its own mirror normal keeps its axis; the other two flip), so the same joint state drives both sides symmetrically. Splice it back with [assembly-join chassis mirrored]. NEVER hand-mirror an assembly.\nPipe: [pipe [cube 50 30 5] [difference [cylinder 3 10]] [fillet 1.0]]\nLet bindings: [let body [cube 50 30 5]]\nScene: [root solid "material-name"], with [material name r g b metallic roughness] to define one\nModules: [use bracket] then [bracket.plate] \u2014 multi-file projects work here, with sources passed in `modules` (or read from `base_dir`); [use bracket :as b] aliases, [use bracket [plate]] imports selectively, and `pub` in a module picks what it exports',
48936
+ description: 'The preferred authoring tool for whole parts and multi-feature models \u2014 one call, full vocabulary. Create a CAD document from loon source code. Loon is a Lisp-like language for parametric CAD \u2014 the FULL modeling vocabulary (patterns, sketches, extrude/revolve/sweep/loft, assemblies) is available here even where no dedicated MCP tool exists. For incremental single-node edits to an open session, use create/update/delete instead.\n\nPrimitives: [cube x y z], [cylinder r h], [sphere r], [cone r-bottom r-top h], [torus major-r minor-r], [wedge x y z], [prism sides radius height]\nBooleans (subject-last): [difference tool subject], [union other subject], [intersection other subject]\nTransforms (subject-last): [translate x y z s], [rotate rx ry rz s], [scale sx sy sz s], [mirror ox oy oz nx ny nz s] (plane through the origin point with that normal) \u2014 plus the axis sugar [mirror-x s] / [mirror-y s] / [mirror-z s], which mirror through the origin, negating that one coordinate. NEVER hand-mirror by negating coordinates; use these.\nFeatures: [fillet r s], [chamfer d s], [shell t s]\nPatterns (subject-last): [linear-pattern dx dy dz count spacing s], [circular-pattern ox oy oz ax ay az count angle s] \u2014 e.g. a bolt circle is [circular-pattern 0 0 0 0 0 1 6 360 bolt-hole]\nSymmetric patterns (subject-last): [mirror-pattern nx ny nz s] and its sugar [mirror-pattern-x s] / -y / -z union a solid with its mirror image (a left/right pair in one expression, so the halves can\'t drift apart); [quad-pattern s] is the 4-fold X-and-Y version \u2014 a quadruped\'s legs, a 4-post frame, a vehicle chassis\nSketches: [sketch ox oy oz xx xy xz yx yy yz #[segments]] with [line x1 y1 x2 y2] and [arc x1 y1 x2 y2 cx cy ccw]\nSketch ops (sketch-last): [extrude dx dy dz sk], [revolve aox aoy aoz adx ady adz angle sk], [sweep-line sx sy sz ex ey ez sk], [sweep-helix radius pitch height turns sk], [loft #[sk1 sk2 \u2026]], [loft-closed #[sk1 sk2 \u2026]]\nAssemblies: [assembly #[parts] #[instances] #[joints] ground-id] with [part name solid "material"], [instance name part-name x y z], [revolute-joint \u2026], [prismatic-joint \u2026], [fixed-joint \u2026], [ball-joint \u2026]\nAssembly symmetry: author ONE side as an assembly, then [mirror-group-x "-r" side] (or -y / -z) returns it plus a mirrored, suffixed copy \u2014 parts reflected, placements and joint anchors mirrored, and joint axes flipped by the correct rule (a hinge across its own mirror normal keeps its axis; the other two flip), so the same joint state drives both sides symmetrically. Splice it back with [assembly-join chassis mirrored]. NEVER hand-mirror an assembly.\nPipe: [pipe [cube 50 30 5] [difference [cylinder 3 10]] [fillet 1.0]]\nLet bindings: [let body [cube 50 30 5]] \u2014 note these are inlined and do NOT survive into the document; use [defparam ...] for a value you want to change later\nParameters (survive into the document and are settable afterwards with set_parameters, and differentiable with parameter_gradient): [defparam pitch_axis_x 310.0], [defparam wall "bore * 0.2"] for derived values, plus optional :unit/:min/:max/:description. Names must be identifier-safe (underscores, not dashes)\nDatums \u2014 named reference geometry, so two parts cannot each hold their own copy of a shared plane: [datum-plane "femur_inner" y 131.0], [datum-axis "pitch" x 0 0 310], [datum-point "hip" 0 0 310], read back with [datum "femur_inner"], [datum+ "femur_inner" 3.0] (3 mm outboard), [datum-x/-y/-z "pitch"]\nStacks \u2014 declarative packing, where each running clearance is a named value instead of an arbitrary number: [stack y "leg" 131.0 [lane "femur_inner" 5.0] [gap "idler_run" 1.0] [lane "idler_boss" 3.0]] declares datum planes leg_femur_inner_lo/_hi, leg_idler_boss_lo/_hi and leg_end; widening leg_idler_run slides everything outboard of it\nScene: [root solid "material-name"], with [material name r g b metallic roughness] to define one\nModules: [use bracket] then [bracket.plate] \u2014 multi-file projects work here, with sources passed in `modules` (or read from `base_dir`); [use bracket :as b] aliases, [use bracket [plate]] imports selectively, and `pub` in a module picks what it exports',
48797
48937
  inputSchema: createCadLoonSchema,
48798
48938
  handler: async (args, ctx) => {
48799
48939
  const useLoons = Array.isArray(args.use_loons) ? args.use_loons : void 0;
@@ -57896,17 +58036,19 @@ function exportCad(input, engine) {
57896
58036
  const filename = String(args.filename ?? "");
57897
58037
  const stepExt = filename.toLowerCase().split(".").pop();
57898
58038
  if (stepExt === "step" || stepExt === "stp") {
57899
- const step = engine.foldedSheetMetalStep(ir);
57900
- if (step === null) {
57901
- throw new Error(
57902
- "STEP export is only available for sheet-metal documents (the folded body needs B-rep bend geometry). Use .stl or .glb for mesh exports."
57903
- );
58039
+ const foldedStep = engine.foldedSheetMetalStep(ir);
58040
+ if (foldedStep !== null) {
58041
+ const bytes3 = new TextEncoder().encode(foldedStep);
58042
+ return deliver(filename, bytes3, {
58043
+ format: stepExt,
58044
+ parts: 1,
58045
+ note: "Folded sheet-metal body (AP214) with cylindrical bend faces \u2014 bends/angles/directions auto-detect in 3D fab pipelines."
58046
+ });
57904
58047
  }
57905
- const bytes2 = new TextEncoder().encode(step);
58048
+ const bytes2 = engine.documentStep(ir);
57906
58049
  return deliver(filename, bytes2, {
57907
58050
  format: stepExt,
57908
- parts: 1,
57909
- note: "Folded sheet-metal body (AP214) with cylindrical bend faces \u2014 bends/angles/directions auto-detect in 3D fab pipelines."
58051
+ note: "BRep AP214 export \u2014 analytic faces (planes/cylinders/spheres/cones/tori/NURBS) preserved through booleans; ready for CNC quoting."
57910
58052
  });
57911
58053
  }
57912
58054
  const scene = engine.evaluate(ir);
@@ -57938,7 +58080,7 @@ function exportCad(input, engine) {
57938
58080
  bytes = toGlbBytes(scene, filename);
57939
58081
  break;
57940
58082
  default:
57941
- throw new Error(`Unsupported format: .${ext}. Use .stl, .glb, or .step (sheet-metal only)`);
58083
+ throw new Error(`Unsupported format: .${ext}. Use .stl, .glb, or .step`);
57942
58084
  }
57943
58085
  return deliver(filename, bytes, {
57944
58086
  format: ext,
@@ -57977,7 +58119,7 @@ var init_export = __esm({
57977
58119
  },
57978
58120
  filename: {
57979
58121
  type: "string",
57980
- description: "Output filename with extension (.stl, .glb, or \u2014 for sheet-metal documents \u2014 .step/.stp), relative to the server working directory (or VCAD_MCP_EXPORT_DIR if set). STEP exports the FOLDED sheet-metal body (AP214) with true cylindrical bend faces sized by the document's shop profile, so fab services with a 3D pipeline (e.g. SendCutSend) auto-detect bends, angles, and directions with zero data entry."
58122
+ description: "Output filename with extension (.stl, .glb, or .step/.stp), relative to the server working directory (or VCAD_MCP_EXPORT_DIR if set). STEP is a BRep AP214 export: booleans, transforms, fillets, and sweeps keep true analytic faces (the format CNC vendors quote from). Sheet-metal documents export the FOLDED body with cylindrical bend faces auto-detected by 3D fab pipelines (e.g. SendCutSend). Parts built from imported meshes have no BRep and are refused by name \u2014 export those as STL."
57981
58123
  },
57982
58124
  joint_state: jointStateSchemaProp
57983
58125
  },
@@ -57987,7 +58129,7 @@ var init_export = __esm({
57987
58129
  {
57988
58130
  name: "export_cad",
57989
58131
  pack: null,
57990
- description: "Export a CAD document to a file. Supports STL (3D printing), GLB (visualization), and \u2014 for sheet-metal documents \u2014 STEP AP214 of the FOLDED body with true cylindrical bend faces (fab 3D pipelines like SendCutSend auto-detect bends/angles/directions; zero data entry). Format is determined by file extension. Pass `joint_state` to export a jointed assembly at a real pose (joint id or name \u2192 degrees, or mm for sliders) instead of its zero pose.",
58132
+ description: "Export a CAD document to a file. Supports STL (3D printing), GLB (visualization), and STEP AP214 (CNC quoting: BRep with true analytic faces, preserved through booleans/transforms/fillets/sweeps; sheet-metal documents export the FOLDED body with cylindrical bend faces that 3D fab pipelines like SendCutSend auto-detect). Mesh-only parts (imported meshes) can't go to STEP and are refused by name \u2014 use STL for those. Format is determined by file extension. Pass `joint_state` to export a jointed assembly at a real pose (joint id or name \u2192 degrees, or mm for sliders) instead of its zero pose.",
57991
58133
  inputSchema: exportCadSchema,
57992
58134
  handler: (a, c) => exportCad(a, c.engine),
57993
58135
  behavior: behavior({})
@@ -58029,6 +58171,18 @@ function listParameters(input) {
58029
58171
  );
58030
58172
  return jsonResult({ count: parameters.length, parameters });
58031
58173
  }
58174
+ function referencedNames(doc) {
58175
+ const out = /* @__PURE__ */ new Set();
58176
+ const harvest = (expr) => {
58177
+ if (typeof expr !== "string") return;
58178
+ for (const v of expr.match(/[A-Za-z_]\w*/g) ?? []) out.add(v);
58179
+ };
58180
+ for (const expr of Object.values(doc.bindings ?? {})) harvest(expr);
58181
+ for (const c of doc.constraints ?? []) {
58182
+ for (const v of Object.values(c)) harvest(v);
58183
+ }
58184
+ return out;
58185
+ }
58032
58186
  async function setParameters(input, engine) {
58033
58187
  const args = input ?? {};
58034
58188
  const documentId = String(args.document_id ?? "");
@@ -58058,6 +58212,18 @@ async function setParameters(input, engine) {
58058
58212
  `Unknown parameter(s): ${unknown2.join(", ")}. Use list_parameters to see declared names.`
58059
58213
  );
58060
58214
  }
58215
+ const referenced = referencedNames(doc);
58216
+ const noEffect = entries.map(([name]) => name).filter((name) => !referenced.has(name)).map((name) => {
58217
+ const value = doc.parameters[name].value;
58218
+ const inputs = typeof value === "string" ? [...new Set(value.match(/[A-Za-z_]\w*/g) ?? [])].filter(
58219
+ (v) => v in doc.parameters && referenced.has(v)
58220
+ ) : [];
58221
+ return {
58222
+ name,
58223
+ reason: typeof value === "string" ? `derived (${JSON.stringify(value)}) \u2014 no field is bound to it` : "no field is bound to it",
58224
+ ...inputs.length ? { set_instead: inputs } : {}
58225
+ };
58226
+ });
58061
58227
  const changed = [];
58062
58228
  for (const [name, value] of entries) {
58063
58229
  const param = doc.parameters[name];
@@ -58079,6 +58245,7 @@ async function setParameters(input, engine) {
58079
58245
  document_id: documentId,
58080
58246
  updated: changed.length,
58081
58247
  changed,
58248
+ ...noEffect.length ? { no_effect: noEffect } : {},
58082
58249
  ...constraintSolve ? { constraint_solve: constraintSolve } : {}
58083
58250
  });
58084
58251
  result.structuredContent = { changed };
@@ -80215,8 +80382,8 @@ var init_server3 = __esm({
80215
80382
  init_order_feed();
80216
80383
  init_animate();
80217
80384
  PKG_VERSION = (() => {
80218
- if ("0.9.4-main.38") {
80219
- return "0.9.4-main.38";
80385
+ if ("0.9.4-main.40") {
80386
+ return "0.9.4-main.40";
80220
80387
  }
80221
80388
  try {
80222
80389
  const req = createRequire2(import.meta.url);
@@ -80225,8 +80392,8 @@ var init_server3 = __esm({
80225
80392
  return "0.0.0";
80226
80393
  }
80227
80394
  })();
80228
- BUILD_SHA = "254d4e9d13825ac74a895590703959d77898e1f3";
80229
- BUILD_TIME = "2026-07-26T13:42:07.736Z";
80395
+ BUILD_SHA = "6cac4f4f2c7c80a9122ee16857ec2b49f2dcd1f4";
80396
+ BUILD_TIME = "2026-07-26T14:38:17.346Z";
80230
80397
  SHORT_SHA = BUILD_SHA === "unknown" ? "unknown" : BUILD_SHA.slice(0, 7);
80231
80398
  VERSION_WITH_BUILD = SHORT_SHA === "unknown" ? PKG_VERSION : `${PKG_VERSION}+${SHORT_SHA}`;
80232
80399
  INSTANCE_ID = randomUUID6().slice(0, 8);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vcad/mcp",
3
- "version": "0.9.4-main.38",
3
+ "version": "0.9.4-main.40",
4
4
  "description": "vcad MCP server — parametric CAD + PCB design tools for AI agents (self-contained: bundled server + kernel WASM)",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -19,7 +19,7 @@
19
19
  },
20
20
  "homepage": "https://vcad.io",
21
21
  "vcadBuild": {
22
- "sha": "254d4e9d13825ac74a895590703959d77898e1f3",
23
- "builtAt": "2026-07-26T13:42:07.736Z"
22
+ "sha": "6cac4f4f2c7c80a9122ee16857ec2b49f2dcd1f4",
23
+ "builtAt": "2026-07-26T14:38:17.346Z"
24
24
  }
25
25
  }
Binary file