@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 +1 -1
- package/index.mjs +186 -19
- package/package.json +3 -3
- package/vcad_kernel_wasm_bg.wasm +0 -0
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
|
|
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
|
-
|
|
48733
|
-
|
|
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
|
|
57900
|
-
if (
|
|
57901
|
-
|
|
57902
|
-
|
|
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 =
|
|
58048
|
+
const bytes2 = engine.documentStep(ir);
|
|
57906
58049
|
return deliver(filename, bytes2, {
|
|
57907
58050
|
format: stepExt,
|
|
57908
|
-
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
80219
|
-
return "0.9.4-main.
|
|
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 = "
|
|
80229
|
-
BUILD_TIME = "2026-07-
|
|
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.
|
|
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": "
|
|
23
|
-
"builtAt": "2026-07-
|
|
22
|
+
"sha": "6cac4f4f2c7c80a9122ee16857ec2b49f2dcd1f4",
|
|
23
|
+
"builtAt": "2026-07-26T14:38:17.346Z"
|
|
24
24
|
}
|
|
25
25
|
}
|
package/vcad_kernel_wasm_bg.wasm
CHANGED
|
Binary file
|