@vcad/mcp 0.10.0-main.94 → 0.10.0-main.96

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 6176496f3a4b9477437d5eec85aea4bc40cde13c at 2026-10-17T18:45:10.765Z. Source: https://github.com/ecto/vcad
9
+ Built from a0671ca49eaf507c48cb4e456b41c67326dc9ab3 at 2026-10-18T01:12:01.234Z. Source: https://github.com/ecto/vcad
package/index.mjs CHANGED
@@ -31224,6 +31224,68 @@ var init_ecad_sync = __esm({
31224
31224
  }
31225
31225
  });
31226
31226
 
31227
+ // ../core/dist/utils/pcb-layers.js
31228
+ function isCopperLayer(layer) {
31229
+ return COPPER_RE.test(layer);
31230
+ }
31231
+ function innerCopperIndex(layer) {
31232
+ const m = COPPER_RE.exec(layer);
31233
+ return m?.[2] ? Number(m[2]) : 0;
31234
+ }
31235
+ function innerCopperLayerName(n) {
31236
+ return `In${n}Cu`;
31237
+ }
31238
+ function copperLayerNames(count) {
31239
+ if (!Number.isInteger(count) || count < 1) {
31240
+ throw new Error(`invalid copper layer count ${count}`);
31241
+ }
31242
+ if (count === 1)
31243
+ return ["FCu"];
31244
+ const inner = Array.from({ length: count - 2 }, (_, i) => innerCopperLayerName(i + 1));
31245
+ return ["FCu", ...inner, "BCu"];
31246
+ }
31247
+ function assertSupportedCopperCount(count) {
31248
+ const ok4 = Number.isInteger(count) && count >= 1 && (count === 1 || count % 2 === 0) && count <= MAX_COPPER_LAYERS;
31249
+ if (!ok4) {
31250
+ throw new Error(`unsupported PCB layer count ${count}: expected 1 or an even number from 2 to ${MAX_COPPER_LAYERS}`);
31251
+ }
31252
+ }
31253
+ function copperSortKey(layer) {
31254
+ if (layer === "FCu")
31255
+ return 0;
31256
+ if (layer === "BCu")
31257
+ return Number.MAX_SAFE_INTEGER;
31258
+ return innerCopperIndex(layer);
31259
+ }
31260
+ function boardCopperLayers(pcb) {
31261
+ const seen = /* @__PURE__ */ new Set();
31262
+ const add = (l) => {
31263
+ if (l && isCopperLayer(l))
31264
+ seen.add(l);
31265
+ };
31266
+ for (const l of pcb?.stackup?.layers ?? [])
31267
+ add(l.layer);
31268
+ for (const t2 of pcb?.traces ?? [])
31269
+ add(t2.layer);
31270
+ for (const z of pcb?.zones ?? [])
31271
+ add(z.layer);
31272
+ for (const v of pcb?.vias ?? []) {
31273
+ add(v.startLayer);
31274
+ add(v.endLayer);
31275
+ }
31276
+ if (seen.size === 0)
31277
+ return ["FCu", "BCu"];
31278
+ return [...seen].sort((a, b) => copperSortKey(a) - copperSortKey(b));
31279
+ }
31280
+ var COPPER_RE, MAX_COPPER_LAYERS;
31281
+ var init_pcb_layers = __esm({
31282
+ "../core/dist/utils/pcb-layers.js"() {
31283
+ "use strict";
31284
+ COPPER_RE = /^(FCu|BCu|In(\d+)Cu)$/;
31285
+ MAX_COPPER_LAYERS = 32;
31286
+ }
31287
+ });
31288
+
31227
31289
  // ../core/dist/stores/document-store.js
31228
31290
  function crdtF64(v) {
31229
31291
  return { F64: v };
@@ -31466,6 +31528,7 @@ var init_document_store = __esm({
31466
31528
  init_ui_store();
31467
31529
  init_parameters_store();
31468
31530
  init_ecad_sync();
31531
+ init_pcb_layers();
31469
31532
  _sceneSettingsFeatureId = null;
31470
31533
  _schematicFeatureId = null;
31471
31534
  _analysisStudiesFeatureId = null;
@@ -32572,28 +32635,13 @@ var init_document_store = __esm({
32572
32635
  const traceWidth = options?.traceWidth ?? 0.15;
32573
32636
  const clearance = options?.clearance ?? 0.15;
32574
32637
  const boardName2 = options?.name ?? "PCB Board";
32575
- const stackupLayers = [];
32576
- stackupLayers.push({ layer: "FCu", copperThickness: 0.035 });
32577
- if (layerCount >= 4) {
32578
- const innerCount = layerCount - 2;
32579
- if (innerCount > 30)
32580
- throw new Error(`layers ${layerCount} exceeds 32 copper layers`);
32581
- const innerLayerNames = Array.from({ length: 30 }, (_, i) => `In${i + 1}Cu`);
32582
- const dielectricPerLayer = thickness / (layerCount - 1);
32583
- for (let i = 0; i < innerCount; i++) {
32584
- stackupLayers.push({
32585
- layer: innerLayerNames[i],
32586
- copperThickness: 0.035,
32587
- dielectricThickness: dielectricPerLayer,
32588
- dielectricEr: 4.5,
32589
- material: "FR4"
32590
- });
32591
- }
32592
- }
32593
- stackupLayers.push({
32594
- layer: "BCu",
32638
+ assertSupportedCopperCount(layerCount);
32639
+ const copperNames = copperLayerNames(layerCount);
32640
+ const dielectricPerLayer = layerCount > 1 ? thickness / (layerCount - 1) : thickness;
32641
+ const stackupLayers = copperNames.map((layer, i) => i === 0 ? { layer, copperThickness: 0.035 } : {
32642
+ layer,
32595
32643
  copperThickness: 0.035,
32596
- dielectricThickness: layerCount >= 4 ? thickness / (layerCount - 1) : thickness,
32644
+ dielectricThickness: dielectricPerLayer,
32597
32645
  dielectricEr: 4.5,
32598
32646
  material: "FR4"
32599
32647
  });
@@ -32620,7 +32668,11 @@ var init_document_store = __esm({
32620
32668
  edgeClearance: 0.25,
32621
32669
  holeToHole: 0.25,
32622
32670
  minAnnularRing: 0.13,
32623
- minDrill: 0.2
32671
+ minDrill: 0.2,
32672
+ // KiCad's microvia defaults (uvia_min_drill / uvia_min_size).
32673
+ minMicroviaDrill: 0.1,
32674
+ minMicroviaDiameter: 0.2,
32675
+ inferredFloors: []
32624
32676
  },
32625
32677
  footprints: [],
32626
32678
  traces: [],
@@ -41728,6 +41780,40 @@ var init_CHANGELOG = __esm({
41728
41780
  "kernel"
41729
41781
  ]
41730
41782
  },
41783
+ {
41784
+ id: "2026-10-17-stackup-layer-roles",
41785
+ version: "0.10.0",
41786
+ date: "2026-10-17",
41787
+ category: "feat",
41788
+ title: "Stackup layer roles inferred from pours",
41789
+ summary: "Plane, split-plane and signal roles are inferred from copper pours; DRC reports signals routed on plane layers (enforcement opt-in).",
41790
+ features: [
41791
+ "pcb",
41792
+ "electronics",
41793
+ "routing"
41794
+ ],
41795
+ mcpTools: [
41796
+ "run_drc",
41797
+ "set_stackup"
41798
+ ]
41799
+ },
41800
+ {
41801
+ id: "2026-10-17-pcb-layer-coverage",
41802
+ version: "0.10.0",
41803
+ date: "2026-10-17",
41804
+ category: "fix",
41805
+ title: "Inner copper beyond In2Cu renders on 6\u201310 layer boards",
41806
+ summary: "Layer colours, toggles, dielectric slabs and copper Z now derive from the board stackup, so In3Cu\u2013In8Cu draw and toggle; new boards up to 10 layers get valid layer names; MCP accepts In7/In8.",
41807
+ features: [
41808
+ "pcb",
41809
+ "electronics",
41810
+ "layers"
41811
+ ],
41812
+ mcpTools: [
41813
+ "get_copper",
41814
+ "render_stackup"
41815
+ ]
41816
+ },
41731
41817
  {
41732
41818
  id: "2026-10-17-pcb-32-copper-layers",
41733
41819
  version: "0.10.0",
@@ -41742,6 +41828,59 @@ var init_CHANGELOG = __esm({
41742
41828
  "ir"
41743
41829
  ]
41744
41830
  },
41831
+ {
41832
+ id: "2026-10-17-pair-router-coupled-legs",
41833
+ version: "0.10.0",
41834
+ date: "2026-10-17",
41835
+ category: "fix",
41836
+ title: "Pair router keeps coupled legs together",
41837
+ summary: "The router no longer rips or shoves one leg of a coupled pair or routes a twin twice; diff-pair gap checks use coupled segments only, matching KiCad.",
41838
+ features: [
41839
+ "pcb",
41840
+ "electronics",
41841
+ "routing"
41842
+ ],
41843
+ mcpTools: [
41844
+ "route_nets",
41845
+ "route_diff_pair",
41846
+ "run_drc"
41847
+ ]
41848
+ },
41849
+ {
41850
+ id: "2026-10-17-neckdown-and-via-floors",
41851
+ version: "0.10.0",
41852
+ date: "2026-10-17",
41853
+ category: "feat",
41854
+ title: "Per-class neck-down and inferred via floors",
41855
+ summary: "Net classes get a neck-down minimum width; via size floors are inferred from the board with provenance reported.",
41856
+ features: [
41857
+ "pcb",
41858
+ "electronics",
41859
+ "routing"
41860
+ ],
41861
+ mcpTools: [
41862
+ "route_nets",
41863
+ "set_design_rules"
41864
+ ]
41865
+ },
41866
+ {
41867
+ id: "2026-10-17-microvias",
41868
+ version: "0.10.0",
41869
+ date: "2026-10-17",
41870
+ category: "feat",
41871
+ title: "Microvias as a via type",
41872
+ summary: "Microvias are a first-class via type with KiCad semantics (adjacent-layer span, own size rules), imported and exported faithfully.",
41873
+ features: [
41874
+ "pcb",
41875
+ "electronics",
41876
+ "routing"
41877
+ ],
41878
+ mcpTools: [
41879
+ "add_via",
41880
+ "import_kicad",
41881
+ "export_kicad"
41882
+ ]
41883
+ },
41745
41884
  {
41746
41885
  id: "2026-10-17-kicad-import-wildcard-layers",
41747
41886
  version: "0.10.0",
@@ -41776,6 +41915,39 @@ var init_CHANGELOG = __esm({
41776
41915
  "export_gerber"
41777
41916
  ]
41778
41917
  },
41918
+ {
41919
+ id: "2026-10-17-drc-inner-layers-in7-in8",
41920
+ version: "0.10.0",
41921
+ date: "2026-10-17",
41922
+ category: "fix",
41923
+ title: "DRC sees In7/In8 copper on 10-layer boards",
41924
+ summary: "The DRC copper stack skipped In7Cu/In8Cu, reporting thousands of false disjoint-net fragments on 10-layer boards.",
41925
+ features: [
41926
+ "pcb",
41927
+ "electronics",
41928
+ "routing"
41929
+ ],
41930
+ mcpTools: [
41931
+ "run_drc"
41932
+ ]
41933
+ },
41934
+ {
41935
+ id: "2026-10-17-diff-pair-si-polish",
41936
+ version: "0.10.0",
41937
+ date: "2026-10-17",
41938
+ category: "feat",
41939
+ title: "Differentiable diff-pair SI polish",
41940
+ summary: "Routed diff pairs are tuned by a tang-based claim compiler with SCO/SQP solvers and mined cuts, improving coupling and skew without breaking connectivity.",
41941
+ features: [
41942
+ "pcb",
41943
+ "electronics",
41944
+ "routing"
41945
+ ],
41946
+ mcpTools: [
41947
+ "route_nets",
41948
+ "route_diff_pair"
41949
+ ]
41950
+ },
41779
41951
  {
41780
41952
  id: "2026-10-16-root-cache-rigid-placement",
41781
41953
  version: "0.10.0",
@@ -49597,6 +49769,7 @@ var init_dist3 = __esm({
49597
49769
  init_logger();
49598
49770
  init_changelog();
49599
49771
  init_sketch_constraint_persist();
49772
+ init_pcb_layers();
49600
49773
  }
49601
49774
  });
49602
49775
 
@@ -54610,7 +54783,7 @@ var init_registry_dispatch = __esm({
54610
54783
 
54611
54784
  // src/tools/pcb-layers.ts
54612
54785
  var INNER_COPPER, PCB_LAYERS, COPPER_STACK;
54613
- var init_pcb_layers = __esm({
54786
+ var init_pcb_layers2 = __esm({
54614
54787
  "src/tools/pcb-layers.ts"() {
54615
54788
  "use strict";
54616
54789
  INNER_COPPER = Array.from({ length: 30 }, (_, i) => `In${i + 1}Cu`);
@@ -54741,7 +54914,7 @@ var VALID_LAYERS;
54741
54914
  var init_pcb_validate = __esm({
54742
54915
  "src/tools/pcb-validate.ts"() {
54743
54916
  "use strict";
54744
- init_pcb_layers();
54917
+ init_pcb_layers2();
54745
54918
  VALID_LAYERS = new Set(PCB_LAYERS);
54746
54919
  }
54747
54920
  });
@@ -62061,7 +62234,11 @@ function defaultDesignRules() {
62061
62234
  edgeClearance: 0.5,
62062
62235
  holeToHole: 0.5,
62063
62236
  minAnnularRing: 0.15,
62064
- minDrill: 0.2
62237
+ minDrill: 0.2,
62238
+ // KiCad's microvia defaults (uvia_min_drill / uvia_min_size).
62239
+ minMicroviaDrill: 0.1,
62240
+ minMicroviaDiameter: 0.2,
62241
+ inferredFloors: []
62065
62242
  };
62066
62243
  }
62067
62244
  function stripDocArgs(args) {
@@ -62201,7 +62378,7 @@ function ecadUnverifiable(check2, outcome) {
62201
62378
  isError: true
62202
62379
  };
62203
62380
  }
62204
- function isCopperLayer(layer) {
62381
+ function isCopperLayer2(layer) {
62205
62382
  return COPPER_LAYER_SET.has(layer);
62206
62383
  }
62207
62384
  function suggestLayer(name) {
@@ -62226,7 +62403,7 @@ function validateLayer(raw) {
62226
62403
  function validateCopperLayer(raw) {
62227
62404
  const res = validateLayer(raw);
62228
62405
  if ("error" in res) return res;
62229
- if (!isCopperLayer(res.layer)) {
62406
+ if (!isCopperLayer2(res.layer)) {
62230
62407
  return {
62231
62408
  error: `layer '${res.layer}' is not a copper layer; copper layers: ${COPPER_LAYERS.join(", ")}`
62232
62409
  };
@@ -63562,7 +63739,8 @@ async function routeNets(args, toolCtx) {
63562
63739
  startLayer: v.start_layer ?? "FCu",
63563
63740
  endLayer: v.end_layer ?? "BCu",
63564
63741
  net: v.net,
63565
- source: "autoroute"
63742
+ source: "autoroute",
63743
+ ...v.via_type ? { viaType: v.via_type } : {}
63566
63744
  });
63567
63745
  viasAdded++;
63568
63746
  }
@@ -66442,7 +66620,7 @@ function searchFootprints(args) {
66442
66620
  };
66443
66621
  }
66444
66622
  function padCopperLayers(pad) {
66445
- return pad.layers.filter((l) => isCopperLayer(l));
66623
+ return pad.layers.filter((l) => isCopperLayer2(l));
66446
66624
  }
66447
66625
  function getPadPositions(args) {
66448
66626
  const ctx = resolveDocInput(args);
@@ -66753,7 +66931,10 @@ async function describePcb(args) {
66753
66931
  edgeClearance: dr.edgeClearance,
66754
66932
  holeToHole: dr.holeToHole,
66755
66933
  minAnnularRing: dr.minAnnularRing,
66756
- minDrill: dr.minDrill
66934
+ minDrill: dr.minDrill,
66935
+ minMicroviaDrill: dr.minMicroviaDrill,
66936
+ minMicroviaDiameter: dr.minMicroviaDiameter,
66937
+ inferredFloors: dr.inferredFloors
66757
66938
  };
66758
66939
  const zones = pcb.zones.map((z) => ({
66759
66940
  net: z.net,
@@ -66987,7 +67168,7 @@ async function setStackup(args) {
66987
67168
  if (copperOz != null) {
66988
67169
  const t2 = round33(copperOz * OZ_TO_MM);
66989
67170
  for (const l of stackup) {
66990
- if (isCopperLayer(l.layer)) l.copperThickness = t2;
67171
+ if (isCopperLayer2(l.layer)) l.copperThickness = t2;
66991
67172
  }
66992
67173
  }
66993
67174
  for (const ov of perLayer ?? []) {
@@ -66999,7 +67180,7 @@ async function setStackup(args) {
66999
67180
  const layerName = layerRes.layer;
67000
67181
  let entry = stackup.find((l) => l.layer === layerName);
67001
67182
  if (!entry) {
67002
- if (!isCopperLayer(layerName)) {
67183
+ if (!isCopperLayer2(layerName)) {
67003
67184
  return fail2(`cannot create non-copper layer "${layerName}" \u2014 only copper layers are auto-added`);
67004
67185
  }
67005
67186
  entry = { layer: layerName };
@@ -70379,7 +70560,7 @@ var init_ecad2 = __esm({
70379
70560
  init_em_claims();
70380
70561
  init_enclosure();
70381
70562
  init_pcb_validate();
70382
- init_pcb_layers();
70563
+ init_pcb_layers2();
70383
70564
  init_ecad_diff();
70384
70565
  init_artifact_store();
70385
70566
  init_remote();
@@ -73823,9 +74004,7 @@ async function renderStackup(args) {
73823
74004
  isError: true
73824
74005
  };
73825
74006
  }
73826
- const declared = new Set(pcb.stackup.layers.map((l) => String(l.layer)));
73827
- const present = COPPER_LAYERS2.filter((l) => declared.has(l));
73828
- const copper = present.length > 0 ? [...present] : ["FCu", "BCu"];
74007
+ const copper = boardCopperLayers(pcb);
73829
74008
  const pcbJson = JSON.stringify(pcb);
73830
74009
  const content = [];
73831
74010
  const index = [];
@@ -73892,7 +74071,7 @@ async function renderStackup(args) {
73892
74071
  });
73893
74072
  return withRenderAssets({ content }, assets);
73894
74073
  }
73895
- var renderViewSchema, SVG_SCALE, DEFAULT_WIDTH_PX, MAX_NODES, MAX_PATTERN_INSTANCES, MAX_RENDER_TRIANGLES, MAX_RASTER_SVG_BYTES, MAX_INLINE_SVG_BYTES, renderPcbSchema, PCB_MARGIN_MM, RATSNEST_COLOR, renderRatsnestSchema, COPPER_LAYERS2, renderStackupSchema, toolDefs24;
74074
+ var renderViewSchema, SVG_SCALE, DEFAULT_WIDTH_PX, MAX_NODES, MAX_PATTERN_INSTANCES, MAX_RENDER_TRIANGLES, MAX_RASTER_SVG_BYTES, MAX_INLINE_SVG_BYTES, renderPcbSchema, PCB_MARGIN_MM, RATSNEST_COLOR, renderRatsnestSchema, renderStackupSchema, toolDefs24;
73896
74075
  var init_render2 = __esm({
73897
74076
  "src/tools/render.ts"() {
73898
74077
  "use strict";
@@ -73903,7 +74082,6 @@ var init_render2 = __esm({
73903
74082
  init_tool_def();
73904
74083
  init_render_assets();
73905
74084
  init_arg_coerce();
73906
- init_pcb_layers();
73907
74085
  init_pose();
73908
74086
  renderViewSchema = {
73909
74087
  type: "object",
@@ -74042,7 +74220,6 @@ var init_render2 = __esm({
74042
74220
  },
74043
74221
  required: ["document_id"]
74044
74222
  };
74045
- COPPER_LAYERS2 = COPPER_STACK;
74046
74223
  renderStackupSchema = {
74047
74224
  type: "object",
74048
74225
  properties: {
@@ -84633,8 +84810,8 @@ var init_server3 = __esm({
84633
84810
  init_order_feed();
84634
84811
  init_animate();
84635
84812
  PKG_VERSION = (() => {
84636
- if ("0.10.0-main.94") {
84637
- return "0.10.0-main.94";
84813
+ if ("0.10.0-main.96") {
84814
+ return "0.10.0-main.96";
84638
84815
  }
84639
84816
  try {
84640
84817
  const req = createRequire2(import.meta.url);
@@ -84643,8 +84820,8 @@ var init_server3 = __esm({
84643
84820
  return "0.0.0";
84644
84821
  }
84645
84822
  })();
84646
- BUILD_SHA = "6176496f3a4b9477437d5eec85aea4bc40cde13c";
84647
- BUILD_TIME = "2026-10-17T18:45:10.765Z";
84823
+ BUILD_SHA = "a0671ca49eaf507c48cb4e456b41c67326dc9ab3";
84824
+ BUILD_TIME = "2026-10-18T01:12:01.234Z";
84648
84825
  SHORT_SHA = BUILD_SHA === "unknown" ? "unknown" : BUILD_SHA.slice(0, 7);
84649
84826
  VERSION_WITH_BUILD = SHORT_SHA === "unknown" ? PKG_VERSION : `${PKG_VERSION}+${SHORT_SHA}`;
84650
84827
  INSTANCE_ID = randomUUID7().slice(0, 8);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vcad/mcp",
3
- "version": "0.10.0-main.94",
3
+ "version": "0.10.0-main.96",
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": "6176496f3a4b9477437d5eec85aea4bc40cde13c",
23
- "builtAt": "2026-10-17T18:45:10.765Z"
22
+ "sha": "a0671ca49eaf507c48cb4e456b41c67326dc9ab3",
23
+ "builtAt": "2026-10-18T01:12:01.234Z"
24
24
  }
25
25
  }
Binary file