@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.
- package/README.md +1 -1
- package/index.mjs +91 -21
- 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
|
|
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 (
|
|
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
|
|
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,
|
|
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.
|
|
81548
|
-
return "0.9.4-main.
|
|
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 = "
|
|
81558
|
-
BUILD_TIME = "2026-07-
|
|
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.
|
|
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": "
|
|
23
|
-
"builtAt": "2026-07-
|
|
22
|
+
"sha": "6da108761001bf4957ffbaef8e90cc4a9f4a8b50",
|
|
23
|
+
"builtAt": "2026-07-29T18:21:09.646Z"
|
|
24
24
|
}
|
|
25
25
|
}
|