@vcad/mcp 0.9.4-main.49 → 0.9.4-main.50

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.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/index.mjs +91 -21
  3. package/package.json +3 -3
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 40ccc073edea8494ce6e1a94ea360bf79cfc630d at 2026-07-29T16:38:39.110Z. Source: https://github.com/ecto/vcad
9
+ Built from 6da108761001bf4957ffbaef8e90cc4a9f4a8b50 at 2026-07-29T18:21:09.646Z. Source: https://github.com/ecto/vcad
package/index.mjs CHANGED
@@ -53582,6 +53582,12 @@ async function handleModernRequest(msg, opts) {
53582
53582
  onNotification: (n) => {
53583
53583
  const nm = n.method;
53584
53584
  if (nm === "notifications/message" && !wantsLogs) return;
53585
+ if (nm === "notifications/progress" && bridgeRef) {
53586
+ const tctx = taskInputHooks.get(bridgeRef);
53587
+ if (tctx && tctx.record.status === "working") {
53588
+ touchTask(tctx.record, void 0, progressStatusMessage(tctx.record.toolName, n));
53589
+ }
53590
+ }
53585
53591
  opts.onNotification?.(n);
53586
53592
  },
53587
53593
  onServerRequest
@@ -53608,6 +53614,7 @@ async function handleModernRequest(msg, opts) {
53608
53614
  version: "0.0.0"
53609
53615
  };
53610
53616
  const forwarded = stripModernFields(params);
53617
+ if (method === "tools/call") ensureProgressToken(forwarded);
53611
53618
  if (asTask) {
53612
53619
  pruneTasks();
53613
53620
  const record2 = createTaskRecord(params.name);
@@ -53682,6 +53689,19 @@ function stripModernFields(params) {
53682
53689
  }
53683
53690
  return out;
53684
53691
  }
53692
+ function ensureProgressToken(forwarded) {
53693
+ const meta = forwarded._meta && typeof forwarded._meta === "object" ? { ...forwarded._meta } : {};
53694
+ if (meta.progressToken === void 0) meta.progressToken = BRIDGE_PROGRESS_TOKEN;
53695
+ forwarded._meta = meta;
53696
+ }
53697
+ function progressStatusMessage(toolName, n) {
53698
+ const p = n.params ?? {};
53699
+ const message = typeof p.message === "string" ? p.message : void 0;
53700
+ const progress = typeof p.progress === "number" ? p.progress : void 0;
53701
+ const total = typeof p.total === "number" ? p.total : void 0;
53702
+ const counter = progress !== void 0 ? total !== void 0 ? ` (${progress}/${total})` : ` (${progress})` : "";
53703
+ return `${message ?? `running ${toolName}`}${counter}`;
53704
+ }
53685
53705
  function createTaskRecord(toolName) {
53686
53706
  const now = (/* @__PURE__ */ new Date()).toISOString();
53687
53707
  const record2 = {
@@ -53840,7 +53860,7 @@ function handleModernListen(msg, sink) {
53840
53860
  }
53841
53861
  };
53842
53862
  }
53843
- var PROTOCOL_2026, BRIDGE_VERSION, SUPPORTED_PROTOCOL_VERSIONS2, META_PROTOCOL_VERSION, META_CLIENT_CAPABILITIES, META_CLIENT_INFO, META_SERVER_INFO, META_LOG_LEVEL, META_SUBSCRIPTION_ID, TASKS_EXTENSION, ERR_HEADER_MISMATCH, ERR_UNSUPPORTED_PROTOCOL_VERSION, ERR_METHOD_NOT_FOUND, ERR_INVALID_PARAMS, ERR_INTERNAL, LEGACY_RESOURCE_NOT_FOUND, LIST_TTL_MS, DISCOVER_TTL_MS, CACHE_SCOPE, CACHEABLE_METHODS, FORWARDED_METHODS, NAME_HEADER_METHODS, MRTR_METHODS, LONG_RUNNING_TOOLS, TASK_TTL_MS, TASK_POLL_INTERVAL_MS, MODERN_ONLY_METHODS, BASE64_SENTINEL_PREFIX, BASE64_SENTINEL_SUFFIX, bus, EVT_TOOLS_CHANGED, EVT_TASK, tasks, taskInputHooks;
53863
+ var PROTOCOL_2026, BRIDGE_VERSION, SUPPORTED_PROTOCOL_VERSIONS2, META_PROTOCOL_VERSION, META_CLIENT_CAPABILITIES, META_CLIENT_INFO, META_SERVER_INFO, META_LOG_LEVEL, META_SUBSCRIPTION_ID, TASKS_EXTENSION, ERR_HEADER_MISMATCH, ERR_UNSUPPORTED_PROTOCOL_VERSION, ERR_METHOD_NOT_FOUND, ERR_INVALID_PARAMS, ERR_INTERNAL, LEGACY_RESOURCE_NOT_FOUND, LIST_TTL_MS, DISCOVER_TTL_MS, CACHE_SCOPE, CACHEABLE_METHODS, FORWARDED_METHODS, NAME_HEADER_METHODS, MRTR_METHODS, LONG_RUNNING_TOOLS, TASK_TTL_MS, TASK_POLL_INTERVAL_MS, MODERN_ONLY_METHODS, BASE64_SENTINEL_PREFIX, BASE64_SENTINEL_SUFFIX, bus, EVT_TOOLS_CHANGED, EVT_TASK, tasks, BRIDGE_PROGRESS_TOKEN, taskInputHooks;
53844
53864
  var init_protocol_2026 = __esm({
53845
53865
  "src/protocol-2026.ts"() {
53846
53866
  "use strict";
@@ -53927,6 +53947,7 @@ var init_protocol_2026 = __esm({
53927
53947
  EVT_TOOLS_CHANGED = "tools_list_changed";
53928
53948
  EVT_TASK = "task";
53929
53949
  tasks = /* @__PURE__ */ new Map();
53950
+ BRIDGE_PROGRESS_TOKEN = "modern-bridge-progress";
53930
53951
  taskInputHooks = /* @__PURE__ */ new WeakMap();
53931
53952
  }
53932
53953
  });
@@ -61108,7 +61129,8 @@ async function netIslandCounts(pcb, nets) {
61108
61129
  }
61109
61130
  return counts;
61110
61131
  }
61111
- async function routeNets(args) {
61132
+ async function routeNets(args, toolCtx) {
61133
+ const progress = toolCtx?.progress;
61112
61134
  const ctx = resolveDocInput(args);
61113
61135
  const doc = ctx.doc;
61114
61136
  const traceWidth = args.trace_width || void 0;
@@ -61126,6 +61148,7 @@ async function routeNets(args) {
61126
61148
  }
61127
61149
  const width = traceWidth || pcb.rules.defaultRules.traceWidth;
61128
61150
  const wantReceipt = Boolean(args.receipt);
61151
+ if (wantReceipt) progress?.(0, void 0, "snapshotting pre-route DRC");
61129
61152
  const beforeSnap = wantReceipt ? await drcPcb(pcb, "full", 500) : null;
61130
61153
  const netConnections = /* @__PURE__ */ new Map();
61131
61154
  for (const fp of pcb.footprints) {
@@ -61261,15 +61284,18 @@ async function routeNets(args) {
61261
61284
  };
61262
61285
  let routedSomething = false;
61263
61286
  if (strategy === "auto") {
61287
+ progress?.(0, void 0, "routing all nets (negotiated whole-board pass)");
61264
61288
  const result = await routeAll(pcb, width, routeFilter, effort);
61265
61289
  routedSomething = result.traces.length > 0 || result.vias.length > 0 || result.unrouted_nets.length > 0;
61266
61290
  if (routedSomething) applyRoute(result);
61267
61291
  } else {
61268
61292
  const universe = routeFilter.length > 0 ? routeFilter : [...netConnections.keys()].filter((n) => !preservedNets.has(n));
61269
61293
  const tiers = [...new Set(universe.map(tierOf))].sort((a, b) => a - b);
61270
- for (const tier of tiers) {
61294
+ for (let ti = 0; ti < tiers.length; ti++) {
61295
+ const tier = tiers[ti];
61271
61296
  const nets = universe.filter((n) => tierOf(n) === tier);
61272
61297
  if (nets.length === 0) continue;
61298
+ progress?.(ti, tiers.length, `routing tier ${ti + 1}/${tiers.length} (${nets.length} net(s))`);
61273
61299
  const result = await routeAll(pcb, width, nets, effort);
61274
61300
  if (result.traces.length > 0 || result.vias.length > 0 || result.unrouted_nets.length > 0) {
61275
61301
  routedSomething = true;
@@ -61304,6 +61330,7 @@ async function routeNets(args) {
61304
61330
  }
61305
61331
  const connectivityRegressions = {};
61306
61332
  if (islandsBefore && copperBefore) {
61333
+ progress?.(0, void 0, "verifying net connectivity");
61307
61334
  const before = islandsBefore;
61308
61335
  const worseNets = async (nets) => {
61309
61336
  const counts = await netIslandCounts(pcb, nets);
@@ -61323,6 +61350,7 @@ async function routeNets(args) {
61323
61350
  if (retrySet.size > 0) {
61324
61351
  pcb.traces = pcb.traces.filter((t2) => !retrySet.has(t2.net) || t2.source === "manual");
61325
61352
  pcb.vias = pcb.vias.filter((v) => !retrySet.has(v.net) || v.source === "manual");
61353
+ progress?.(0, void 0, `re-routing ${retrySet.size} net(s) with regressed connectivity`);
61326
61354
  const retried = await routeAll(pcb, width, [...retrySet], effort);
61327
61355
  applyRoute(retried);
61328
61356
  }
@@ -61615,7 +61643,8 @@ async function routeDiffPair2(args) {
61615
61643
  ]
61616
61644
  };
61617
61645
  }
61618
- async function lengthMatchTraces(args) {
61646
+ async function lengthMatchTraces(args, toolCtx) {
61647
+ const progress = toolCtx?.progress;
61619
61648
  const ctx = resolveDocInput(args);
61620
61649
  const pcb = getDocPcb2(ctx.doc);
61621
61650
  const fail2 = ecadError;
@@ -61631,6 +61660,7 @@ async function lengthMatchTraces(args) {
61631
61660
  if (style !== void 0 && style !== "trombone" && style !== "sawtooth") {
61632
61661
  return fail2("style must be 'trombone' or 'sawtooth'");
61633
61662
  }
61663
+ progress?.(0, void 0, `length-matching ${nets.length} net(s)`);
61634
61664
  const result = await matchTraceLengths(pcb, nets, {
61635
61665
  target_length: args.target_length,
61636
61666
  tolerance: args.tolerance,
@@ -61671,6 +61701,9 @@ async function lengthMatchTraces(args) {
61671
61701
  };
61672
61702
  }
61673
61703
  const tuned = result.nets.filter((n) => n.tuned && n.new_traces && n.new_traces.length > 0);
61704
+ if (tuned.length > 0) {
61705
+ progress?.(0, void 0, `verifying DRC delta for ${tuned.length} tuned net(s)`);
61706
+ }
61674
61707
  const touched = new Set(tuned.map((n) => n.net));
61675
61708
  const newPoints = tuned.flatMap(
61676
61709
  (n) => (n.new_traces ?? []).flatMap((t2) => [t2.start, t2.end])
@@ -67659,7 +67692,8 @@ function onBoard(p, outline) {
67659
67692
  function samePoint(a, b, eps = FIX_EPS) {
67660
67693
  return Math.abs(a.x - b.x) <= eps && Math.abs(a.y - b.y) <= eps;
67661
67694
  }
67662
- async function fixDrc(args) {
67695
+ async function fixDrc(args, toolCtx) {
67696
+ const progress = toolCtx?.progress;
67663
67697
  const ctx = resolveDocInput(args);
67664
67698
  const pcb = getDocPcb2(ctx.doc);
67665
67699
  if (!pcb) {
@@ -67675,6 +67709,7 @@ async function fixDrc(args) {
67675
67709
  const dryRun = Boolean(args.dry_run);
67676
67710
  const effort = Math.min(100, Math.max(0.1, Number(args.reroute_effort) || 4));
67677
67711
  const maxFixes = Math.max(1, Math.round(Number(args.max_fixes) || 50));
67712
+ progress?.(0, void 0, "running initial DRC");
67678
67713
  const before = await drcPcb(pcb, "full", 20);
67679
67714
  if (!before.success) return ecadUnverifiable("fix_drc", before);
67680
67715
  const viols = before.details ?? [];
@@ -67687,7 +67722,9 @@ async function fixDrc(args) {
67687
67722
  if (existing) existing.count++;
67688
67723
  else skipped.push({ rule, reason, count: 1, ...message ? { sample_message: message } : {} });
67689
67724
  };
67725
+ let fixAttempts = 0;
67690
67726
  const applyVerified = async (bounds, mutate) => {
67727
+ progress?.(++fixAttempts, void 0, `verifying fix ${fixAttempts} (${fixed.length} applied so far)`);
67691
67728
  const savedTraces = pcb.traces;
67692
67729
  const savedVias = pcb.vias;
67693
67730
  const cap = await beginDrcDelta(pcb, bounds);
@@ -67979,6 +68016,7 @@ async function fixDrc(args) {
67979
68016
  budget--;
67980
68017
  continue;
67981
68018
  }
68019
+ progress?.(++fixAttempts, void 0, `re-routing net '${net}' (${fixed.length} fix(es) applied so far)`);
67982
68020
  const savedTraces = pcb.traces;
67983
68021
  const savedVias = pcb.vias;
67984
68022
  const cap = await beginDrcDelta(pcb, "full");
@@ -68010,6 +68048,7 @@ async function fixDrc(args) {
68010
68048
  const reason = FIX_DRC_NEVER[v.rule];
68011
68049
  if (reason) skip(v.rule, reason, v.message);
68012
68050
  }
68051
+ if (!dryRun) progress?.(0, void 0, "running final DRC");
68013
68052
  const after = dryRun ? before : await drcPcb(pcb, "full", 20);
68014
68053
  const brief = (s) => ({
68015
68054
  violations: s.violations,
@@ -69678,7 +69717,7 @@ var init_ecad2 = __esm({
69678
69717
  pack: "ecad",
69679
69718
  description: "Route electrical nets on the PCB with copper traces. Connects pads belonging to the same net. Idempotent: re-running rips up the previously autorouted copper on the target nets before routing, so a second call replaces the route instead of stacking shorts. Hand-placed copper (add_trace / add_via / coils) is preserved automatically; `locked_nets` additionally protects whole nets. A net with a copper-pour zone (a plane) is connected by stitching each pad to the plane with a via instead of tracing it \u2014 those nets come back in `plane_stitched`. Mutates the session document (pass document_id).",
69680
69719
  inputSchema: routeNetsSchema,
69681
- handler: (a) => routeNets(a),
69720
+ handler: (a, c) => routeNets(a, c),
69682
69721
  behavior: behavior({ writesDoc: true, geometry: true })
69683
69722
  },
69684
69723
  {
@@ -69960,7 +69999,7 @@ var init_ecad2 = __esm({
69960
69999
  pack: "ecad",
69961
70000
  description: "Run DRC and automatically apply the mechanically-safe subset of fixes: stitching vias for UnstitchedPad, dedupe of overlapping same-net via drills (HoleToHole), inward nudges for EdgeClearance when a legal corridor exists, and per-net rip-up + re-route (at higher effort) for UnconnectedNet/NetIslands. Every fix is individually verified with a DRC delta and REVERTED if it would introduce any new violation. Never touches design decisions: different-net shorts/clearance, courtyard overlaps, keepouts, or anything requiring a component move. Returns a fail-closed receipt: before/after violation counts, what was fixed, and what was skipped with the reason. `dry_run` plans without mutating. Mutates the session document (pass document_id).",
69962
70001
  inputSchema: fixDrcSchema,
69963
- handler: (a) => fixDrc(a),
70002
+ handler: (a, c) => fixDrc(a, c),
69964
70003
  behavior: behavior({ writesDoc: true, geometry: true })
69965
70004
  },
69966
70005
  {
@@ -70024,7 +70063,7 @@ var init_ecad2 = __esm({
70024
70063
  pack: null,
70025
70064
  description: "Length-match a group of routed nets (a DDR lane, clock tree, SPI bus): measures each net's copper and grows the shorter ones with clearance-checked trombone/sawtooth meanders until all reach the longest net (or target_length) within tolerance. Nets it can't tune (branching, multi-layer, arcs, no room) are reported with a reason, never guessed at. check_only:true measures and verdicts without touching copper. Mutating runs carry drc_delta.",
70026
70065
  inputSchema: lengthMatchTracesSchema,
70027
- handler: (a) => lengthMatchTraces(a),
70066
+ handler: (a, c) => lengthMatchTraces(a, c),
70028
70067
  behavior: behavior({ writesDoc: true, geometry: true })
70029
70068
  },
70030
70069
  {
@@ -77467,12 +77506,22 @@ async function minimizeEnergyTool(input) {
77467
77506
  return fail(err7);
77468
77507
  }
77469
77508
  }
77470
- async function mdRun(input) {
77509
+ async function mdRun(input, toolCtx) {
77471
77510
  try {
77472
77511
  const args = input;
77473
77512
  const env = await MdEnv.create(args.molecule, args.config ?? {});
77474
77513
  try {
77475
- const observation = env.run(args.steps);
77514
+ const total = Math.max(1, Math.round(args.steps));
77515
+ const chunk = toolCtx?.progress ? Math.max(1, Math.ceil(total / 10)) : total;
77516
+ let done = 0;
77517
+ let observation = env.run(Math.min(chunk, total));
77518
+ done += Math.min(chunk, total);
77519
+ while (done < total) {
77520
+ toolCtx?.progress?.(done, total, `MD step ${done}/${total}`);
77521
+ const n = Math.min(chunk, total - done);
77522
+ observation = env.run(n);
77523
+ done += n;
77524
+ }
77476
77525
  const molecule = env.molecule();
77477
77526
  return okPretty({ observation, molecule });
77478
77527
  } finally {
@@ -77508,7 +77557,7 @@ function scaleMolecule(mol, s) {
77508
77557
  } : mol.cell;
77509
77558
  return { ...mol, positions, cell };
77510
77559
  }
77511
- async function designMaterial(input) {
77560
+ async function designMaterial(input, toolCtx) {
77512
77561
  try {
77513
77562
  const args = input;
77514
77563
  const [lo0, hi0] = args.scale_bounds ?? [0.5, 2];
@@ -77536,6 +77585,7 @@ async function designMaterial(input) {
77536
77585
  let s = 1;
77537
77586
  let prop = await measure2(base);
77538
77587
  for (let it = 0; it < 60; it++) {
77588
+ toolCtx?.progress?.(it, 60, `bisection iteration ${it + 1}: property ${prop.toFixed(4)} \u2192 target ${args.target}`);
77539
77589
  s = 0.5 * (lo + hi);
77540
77590
  prop = await measure2(scaleMolecule(base, s));
77541
77591
  const tooSmall = increasing ? prop < args.target : prop > args.target;
@@ -77866,7 +77916,7 @@ var init_atoms2 = __esm({
77866
77916
  pack: "atoms",
77867
77917
  description: "Run molecular dynamics (velocity-Verlet, optional Berendsen thermostat) for N steps and return the final observation (energies, temperature, max force) and the evolved structure.",
77868
77918
  inputSchema: mdRunSchema,
77869
- handler: (a) => mdRun(a),
77919
+ handler: (a, c) => mdRun(a, c),
77870
77920
  behavior: behavior({})
77871
77921
  },
77872
77922
  {
@@ -77874,7 +77924,7 @@ var init_atoms2 = __esm({
77874
77924
  pack: "atoms",
77875
77925
  description: "Inverse design: search an isotropic scale factor that drives a geometric property (nearest-neighbor distance or radius of gyration) to a target value, returning the reshaped molecule and a receipt. The energy-objective inverse design (gradients through the simulation) lives in the Rust kernel.",
77876
77926
  inputSchema: designMaterialSchema,
77877
- handler: (a) => designMaterial(a),
77927
+ handler: (a, c) => designMaterial(a, c),
77878
77928
  behavior: behavior({})
77879
77929
  },
77880
77930
  {
@@ -79835,7 +79885,7 @@ function explodeDirections(doc, transforms) {
79835
79885
  });
79836
79886
  return dirs;
79837
79887
  }
79838
- function buildSequenceGlb(doc, timeline, frames, engine) {
79888
+ function buildSequenceGlb(doc, timeline, frames, engine, onProgress) {
79839
79889
  const channels = [];
79840
79890
  const meshes = [];
79841
79891
  const paramFrames = frames.filter((f) => f.geometryDirty);
@@ -79938,6 +79988,7 @@ function buildSequenceGlb(doc, timeline, frames, engine) {
79938
79988
  geoSamples = sampled.length;
79939
79989
  const labels = buildPartLabels(doc);
79940
79990
  for (let k = 0; k < sampled.length; k++) {
79991
+ onProgress?.(k, sampled.length, `evaluating geometry sample ${k + 1}/${sampled.length}`);
79941
79992
  const frame = sampled[k];
79942
79993
  const posed = poseDocument(doc, frame);
79943
79994
  let scene;
@@ -80028,9 +80079,10 @@ ${issues.map((i) => i.problem).join("\n")}`
80028
80079
  `sequence has ${frames.length} frames (max ${MAX_FRAMES}); lower fps or duration.`
80029
80080
  );
80030
80081
  }
80031
- const built = buildSequenceGlb(doc, timeline, frames, ctx.engine);
80082
+ const built = buildSequenceGlb(doc, timeline, frames, ctx.engine, ctx.progress);
80032
80083
  if (!built) return err2("document has no previewable geometry to animate.");
80033
80084
  const wantVerify = args.verify !== false;
80085
+ if (wantVerify) ctx.progress?.(frames.length, frames.length, "verifying clearance specs");
80034
80086
  const verification = wantVerify ? verifySequenceClearance(doc, frames, ctx.engine) : null;
80035
80087
  const b64 = Buffer.from(built.glb).toString("base64");
80036
80088
  const body = {
@@ -80268,6 +80320,7 @@ ${issues.map((i) => i.problem).join("\n")}`);
80268
80320
  return err2(message);
80269
80321
  };
80270
80322
  for (let i = 0; i < frames.length; i++) {
80323
+ ctx.progress?.(i, frames.length, `rendering frame ${i + 1}/${frames.length}`);
80271
80324
  const frame = frames[i];
80272
80325
  const posed = poseDocument(doc, frame);
80273
80326
  let svg;
@@ -80322,6 +80375,7 @@ ${issues.map((i) => i.problem).join("\n")}`);
80322
80375
  }
80323
80376
  }
80324
80377
  if (!size) return err2("no frames rendered.");
80378
+ ctx.progress?.(frames.length, frames.length, "encoding video");
80325
80379
  let bytes;
80326
80380
  let mime;
80327
80381
  let filename;
@@ -81162,8 +81216,24 @@ async function createServer(existingEngine, context = { user: null }) {
81162
81216
  } catch {
81163
81217
  }
81164
81218
  };
81165
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
81219
+ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
81166
81220
  const { name, arguments: args = {} } = request.params;
81221
+ const progressToken = request.params._meta?.progressToken;
81222
+ const callCtx = progressToken === void 0 ? ctx : {
81223
+ ...ctx,
81224
+ progress: (current, total, message) => {
81225
+ void extra.sendNotification({
81226
+ method: "notifications/progress",
81227
+ params: {
81228
+ progressToken,
81229
+ progress: current,
81230
+ ...total !== void 0 ? { total } : {},
81231
+ ...message !== void 0 ? { message } : {}
81232
+ }
81233
+ }).catch(() => {
81234
+ });
81235
+ }
81236
+ };
81167
81237
  if (disabledTools.has(name)) {
81168
81238
  const pack = dispatchMap.get(name)?.pack;
81169
81239
  const enableHint = pack ? `Enable it with set_tool_packs({ enable: ["${pack}"] }) or set VCAD_MCP_PACKS.` : "Enable its pack to use it.";
@@ -81221,7 +81291,7 @@ async function createServer(existingEngine, context = { user: null }) {
81221
81291
  fireToolAlert(name, args, refusal);
81222
81292
  return refusal;
81223
81293
  }
81224
- const result = await def.handler(args, ctx);
81294
+ const result = await def.handler(args, callCtx);
81225
81295
  if (def.behavior.geometry && result.content.length > 0 && !result.isError) {
81226
81296
  const docId = resolvePreviewDocumentId(name, result, args, engine);
81227
81297
  if (docId) {
@@ -81544,8 +81614,8 @@ var init_server3 = __esm({
81544
81614
  init_order_feed();
81545
81615
  init_animate();
81546
81616
  PKG_VERSION = (() => {
81547
- if ("0.9.4-main.49") {
81548
- return "0.9.4-main.49";
81617
+ if ("0.9.4-main.50") {
81618
+ return "0.9.4-main.50";
81549
81619
  }
81550
81620
  try {
81551
81621
  const req = createRequire2(import.meta.url);
@@ -81554,8 +81624,8 @@ var init_server3 = __esm({
81554
81624
  return "0.0.0";
81555
81625
  }
81556
81626
  })();
81557
- BUILD_SHA = "40ccc073edea8494ce6e1a94ea360bf79cfc630d";
81558
- BUILD_TIME = "2026-07-29T16:38:39.110Z";
81627
+ BUILD_SHA = "6da108761001bf4957ffbaef8e90cc4a9f4a8b50";
81628
+ BUILD_TIME = "2026-07-29T18:21:09.646Z";
81559
81629
  SHORT_SHA = BUILD_SHA === "unknown" ? "unknown" : BUILD_SHA.slice(0, 7);
81560
81630
  VERSION_WITH_BUILD = SHORT_SHA === "unknown" ? PKG_VERSION : `${PKG_VERSION}+${SHORT_SHA}`;
81561
81631
  INSTANCE_ID = randomUUID7().slice(0, 8);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vcad/mcp",
3
- "version": "0.9.4-main.49",
3
+ "version": "0.9.4-main.50",
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": "40ccc073edea8494ce6e1a94ea360bf79cfc630d",
23
- "builtAt": "2026-07-29T16:38:39.110Z"
22
+ "sha": "6da108761001bf4957ffbaef8e90cc4a9f4a8b50",
23
+ "builtAt": "2026-07-29T18:21:09.646Z"
24
24
  }
25
25
  }