@vcad/mcp 0.9.4-main.47 → 0.9.4-main.48

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 e8c30217ef94fd492ae13caee599b581d8334d34 at 2026-07-26T17:13:18.437Z. Source: https://github.com/ecto/vcad
9
+ Built from fe62ea0789005cd4b3f00777274323698634167d at 2026-07-29T16:12:24.504Z. Source: https://github.com/ecto/vcad
package/index.mjs CHANGED
@@ -6180,22 +6180,6 @@ var init_vcad_kernel_wasm = __esm({
6180
6180
  resetAccumulation() {
6181
6181
  wasm.raytracer_resetAccumulation(this.__wbg_ptr);
6182
6182
  }
6183
- /**
6184
- * Set SSAO (screen-space ambient occlusion) parameters.
6185
- *
6186
- * # Arguments
6187
- * * `radius` - World-space hemisphere sample radius (default 0.3)
6188
- * * `intensity` - Occlusion strength: 0 = disabled, 1 = default (>1 stylized)
6189
- * * `bias` - Depth bias to prevent self-occlusion (default 0.001)
6190
- * * `sample_count` - Hemisphere samples per frame: 8, 16, or 32 (default 16)
6191
- * @param {number} radius
6192
- * @param {number} intensity
6193
- * @param {number} bias
6194
- * @param {number} sample_count
6195
- */
6196
- setAO(radius, intensity, bias, sample_count) {
6197
- wasm.raytracer_setAO(this.__wbg_ptr, radius, intensity, bias, sample_count);
6198
- }
6199
6183
  /**
6200
6184
  * Set the debug render mode.
6201
6185
  *
@@ -6251,12 +6235,6 @@ var init_vcad_kernel_wasm = __esm({
6251
6235
  wasm.raytracer_setEdgeStyle(this.__wbg_ptr, enable_silhouette, enable_crease, enable_boundary, silhouette_r, silhouette_g, silhouette_b, silhouette_a, crease_r, crease_g, crease_b, crease_a, boundary_r, boundary_g, boundary_b, boundary_a, silhouette_width, crease_width, boundary_width, edge_softness);
6252
6236
  }
6253
6237
  /**
6254
- * Set the material for all faces in the scene.
6255
- *
6256
- * # Arguments
6257
- * * `r`, `g`, `b` - RGB color components (0-1 range, linear)
6258
- * * `metallic` - Metallic factor (0 = dielectric, 1 = metal)
6259
- * * `roughness` - Roughness factor (0 = smooth/mirror, 1 = rough/diffuse)
6260
6238
  * @param {number} r
6261
6239
  * @param {number} g
6262
6240
  * @param {number} b
@@ -6269,6 +6247,57 @@ var init_vcad_kernel_wasm = __esm({
6269
6247
  throw takeFromExternrefTable0(ret[0]);
6270
6248
  }
6271
6249
  }
6250
+ /**
6251
+ * Set the material for all faces in the scene.
6252
+ *
6253
+ * # Arguments
6254
+ * * `r`, `g`, `b` - RGB color components (0-1 range, linear)
6255
+ * * `metallic` - Metallic factor (0 = dielectric, 1 = metal)
6256
+ * * `roughness` - Roughness factor (0 = smooth/mirror, 1 = rough/diffuse)
6257
+ * Set the material from a serialized IR `MaterialDef`.
6258
+ *
6259
+ * Preferred over `setMaterial`: that one only carries colour, metallic and
6260
+ * roughness, so clearcoat, IOR and anisotropy never reached the viewport
6261
+ * and a brushed or lacquered part shaded differently here than under
6262
+ * `vcad-render --photoreal`. This runs the SAME derivation the CPU
6263
+ * renderer uses (`Pbr::from_material_def`), so both agree by construction.
6264
+ *
6265
+ * `json` is a `MaterialDef` object; pass `null`/empty to fall back to the
6266
+ * optional `tint` (linear RGB) or the neutral default.
6267
+ * @param {string | null} [json]
6268
+ * @param {Float64Array | null} [tint]
6269
+ */
6270
+ setMaterialFromDef(json, tint) {
6271
+ var ptr0 = isLikeNone(json) ? 0 : passStringToWasm0(json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
6272
+ var len0 = WASM_VECTOR_LEN;
6273
+ var ptr1 = isLikeNone(tint) ? 0 : passArrayF64ToWasm0(tint, wasm.__wbindgen_malloc);
6274
+ var len1 = WASM_VECTOR_LEN;
6275
+ const ret = wasm.raytracer_setMaterialFromDef(this.__wbg_ptr, ptr0, len0, ptr1, len1);
6276
+ if (ret[1]) {
6277
+ throw takeFromExternrefTable0(ret[0]);
6278
+ }
6279
+ }
6280
+ /**
6281
+ * Set the path tracer's quality ceiling and stylisation mode.
6282
+ *
6283
+ * Replaces the old `setAO`. The renderer is a real path tracer now, so
6284
+ * screen-space ambient occlusion is gone — multi-bounce GI computes
6285
+ * contact occlusion correctly, and stacking a proxy on top of it would
6286
+ * double-darken every concave corner.
6287
+ *
6288
+ * # Arguments
6289
+ * * `max_depth` - Ceiling on path length (1 = direct lighting only,
6290
+ * default 6, which matches `vcad-render --photoreal`). Actual depth
6291
+ * escalates with accumulation, so the draft frame stays interactive
6292
+ * regardless of this value.
6293
+ * * `stylize` - Draw the Sobel edge overlay. Turn this OFF for a
6294
+ * photoreal viewport: edge lines fight photorealism.
6295
+ * @param {number} max_depth
6296
+ * @param {boolean} stylize
6297
+ */
6298
+ setPathTrace(max_depth, stylize) {
6299
+ wasm.raytracer_setPathTrace(this.__wbg_ptr, max_depth, stylize);
6300
+ }
6272
6301
  /**
6273
6302
  * Set the adaptive refinement sample count.
6274
6303
  *
@@ -13733,10 +13762,10 @@ function isValidJWT(token, algorithm = null) {
13733
13762
  const tokensParts = token.split(".");
13734
13763
  if (tokensParts.length !== 3)
13735
13764
  return false;
13736
- const [header] = tokensParts;
13737
- if (!header)
13765
+ const [header2] = tokensParts;
13766
+ if (!header2)
13738
13767
  return false;
13739
- const parsedHeader = JSON.parse(atob(header));
13768
+ const parsedHeader = JSON.parse(atob(header2));
13740
13769
  if ("typ" in parsedHeader && parsedHeader?.typ !== "JWT")
13741
13770
  return false;
13742
13771
  if (!parsedHeader.alg)
@@ -18655,9 +18684,9 @@ var init_protocol = __esm({
18655
18684
  });
18656
18685
  this.setRequestHandler(ListTasksRequestSchema, async (request, extra) => {
18657
18686
  try {
18658
- const { tasks, nextCursor } = await this._taskStore.listTasks(request.params?.cursor, extra.sessionId);
18687
+ const { tasks: tasks2, nextCursor } = await this._taskStore.listTasks(request.params?.cursor, extra.sessionId);
18659
18688
  return {
18660
- tasks,
18689
+ tasks: tasks2,
18661
18690
  nextCursor,
18662
18691
  _meta: {}
18663
18692
  };
@@ -18804,7 +18833,7 @@ var init_protocol = __esm({
18804
18833
  const capturedTransport = this._transport;
18805
18834
  const relatedTaskId = request.params?._meta?.[RELATED_TASK_META_KEY]?.taskId;
18806
18835
  if (handler === void 0) {
18807
- const errorResponse = {
18836
+ const errorResponse2 = {
18808
18837
  jsonrpc: "2.0",
18809
18838
  id: request.id,
18810
18839
  error: {
@@ -18815,11 +18844,11 @@ var init_protocol = __esm({
18815
18844
  if (relatedTaskId && this._taskMessageQueue) {
18816
18845
  this._enqueueTaskMessage(relatedTaskId, {
18817
18846
  type: "error",
18818
- message: errorResponse,
18847
+ message: errorResponse2,
18819
18848
  timestamp: Date.now()
18820
18849
  }, capturedTransport?.sessionId).catch((error2) => this._onerror(new Error(`Failed to enqueue error response: ${error2}`)));
18821
18850
  } else {
18822
- capturedTransport?.send(errorResponse).catch((error2) => this._onerror(new Error(`Failed to send an error response: ${error2}`)));
18851
+ capturedTransport?.send(errorResponse2).catch((error2) => this._onerror(new Error(`Failed to send an error response: ${error2}`)));
18823
18852
  }
18824
18853
  return;
18825
18854
  }
@@ -18889,7 +18918,7 @@ var init_protocol = __esm({
18889
18918
  if (abortController.signal.aborted) {
18890
18919
  return;
18891
18920
  }
18892
- const errorResponse = {
18921
+ const errorResponse2 = {
18893
18922
  jsonrpc: "2.0",
18894
18923
  id: request.id,
18895
18924
  error: {
@@ -18901,11 +18930,11 @@ var init_protocol = __esm({
18901
18930
  if (relatedTaskId && this._taskMessageQueue) {
18902
18931
  await this._enqueueTaskMessage(relatedTaskId, {
18903
18932
  type: "error",
18904
- message: errorResponse,
18933
+ message: errorResponse2,
18905
18934
  timestamp: Date.now()
18906
18935
  }, capturedTransport?.sessionId);
18907
18936
  } else {
18908
- await capturedTransport?.send(errorResponse);
18937
+ await capturedTransport?.send(errorResponse2);
18909
18938
  }
18910
18939
  }).catch((error2) => this._onerror(new Error(`Failed to send response: ${error2}`))).finally(() => {
18911
18940
  if (this._requestHandlerAbortControllers.get(request.id) === abortController) {
@@ -41040,6 +41069,18 @@ var init_CHANGELOG = __esm({
41040
41069
  CHANGELOG_default = {
41041
41070
  $schema: "./changelog.schema.json",
41042
41071
  entries: [
41072
+ {
41073
+ id: "2026-07-28-mcp-2026-07-28-protocol",
41074
+ version: "0.9.4",
41075
+ date: "2026-07-28",
41076
+ category: "feat",
41077
+ title: "MCP 2026-07-28 protocol support",
41078
+ summary: "The vcad MCP server now fully speaks the stateless 2026-07-28 revision \u2014 server/discover, MRTR, the Tasks extension, subscriptions/listen, and streamed progress \u2014 alongside every earlier revision.",
41079
+ features: [
41080
+ "mcp"
41081
+ ],
41082
+ mcpTools: []
41083
+ },
41043
41084
  {
41044
41085
  id: "2026-07-26-viewport-path-tracer",
41045
41086
  version: "0.9.4",
@@ -41073,6 +41114,21 @@ var init_CHANGELOG = __esm({
41073
41114
  "verify_receipt"
41074
41115
  ]
41075
41116
  },
41117
+ {
41118
+ id: "2026-07-26-step-export-product-anchor",
41119
+ version: "0.9.4",
41120
+ date: "2026-07-26",
41121
+ category: "fix",
41122
+ title: "STEP exports now open in external CAD",
41123
+ summary: "Exported STEP files carry the AP214 product/representation anchor and mm units, so Shapr3D, SolidWorks, and Fusion no longer reject them as containing no 3D geometry.",
41124
+ features: [
41125
+ "step-export",
41126
+ "interop"
41127
+ ],
41128
+ mcpTools: [
41129
+ "export_cad"
41130
+ ]
41131
+ },
41076
41132
  {
41077
41133
  id: "2026-07-26-step-export-booleans",
41078
41134
  version: "0.9.4",
@@ -41090,6 +41146,19 @@ var init_CHANGELOG = __esm({
41090
41146
  "export_cad"
41091
41147
  ]
41092
41148
  },
41149
+ {
41150
+ id: "2026-07-26-step-analytic-circle-edges",
41151
+ version: "0.9.4",
41152
+ date: "2026-07-26",
41153
+ category: "fix",
41154
+ title: "STEP export: curved faces survive third-party import",
41155
+ summary: "Circular edges now export as analytic CIRCLEs instead of chord polylines, so importers like Shapr3D keep cylinder walls and annular faces at the spec 1e-6 accuracy.",
41156
+ features: [
41157
+ "step",
41158
+ "export",
41159
+ "kernel"
41160
+ ]
41161
+ },
41093
41162
  {
41094
41163
  id: "2026-07-26-render-loon-directly",
41095
41164
  version: "0.9.4",
@@ -71089,7 +71158,7 @@ function listEvalTasks(args) {
71089
71158
  }
71090
71159
  const tasksDir = join3(mechevalRoot, "tasks");
71091
71160
  const suiteFilter = args.suite ? String(args.suite).toUpperCase() : null;
71092
- const tasks = [];
71161
+ const tasks2 = [];
71093
71162
  for (const file of readdirSync2(tasksDir).sort()) {
71094
71163
  if (!file.endsWith(".json")) continue;
71095
71164
  try {
@@ -71097,7 +71166,7 @@ function listEvalTasks(args) {
71097
71166
  if (suiteFilter && String(raw.suite).toUpperCase() !== suiteFilter) {
71098
71167
  continue;
71099
71168
  }
71100
- tasks.push({
71169
+ tasks2.push({
71101
71170
  id: raw.id,
71102
71171
  suite: raw.suite,
71103
71172
  tier: raw.tier,
@@ -71109,7 +71178,7 @@ function listEvalTasks(args) {
71109
71178
  } catch {
71110
71179
  }
71111
71180
  }
71112
- return textResult({ count: tasks.length, tasks });
71181
+ return textResult({ count: tasks2.length, tasks: tasks2 });
71113
71182
  }
71114
71183
  async function verifyPart(args) {
71115
71184
  const documentId = String(args.document_id ?? "");
@@ -79908,7 +79977,7 @@ function getBuildInfo() {
79908
79977
  };
79909
79978
  }
79910
79979
  function buildInstructions(kernelPrompt) {
79911
- const header = [
79980
+ const header2 = [
79912
79981
  "vcad \u2014 parametric CAD with a real BRep kernel. Coordinate system: Z-up (X right, Y forward, Z up). Units: millimeters.",
79913
79982
  "",
79914
79983
  "Workflow: `open_document` \u2192 author \u2192 see \u2192 measure \u2192 ship.",
@@ -79926,7 +79995,7 @@ function buildInstructions(kernelPrompt) {
79926
79995
  "",
79927
79996
  "PCB workflow: `create_schematic` (declare connectivity as data via `nets`) \u2192 `place_components` \u2192 `route_nets` / `add_coil` / `add_coil_array` \u2192 `run_drc` \u2192 `validate_for_fab` \u2192 `export_gerber`. All take the `document_id` from create_schematic and mutate that session \u2014 never re-send the document. `validate_for_fab` is the single 'is this board ready?' gate (DRC + renderability + Gerber serialization + blockers, all fail-closed); `export_gerber` enforces a clean DRC by default and blocks a dirty board. `board_from_solid` turns a solid part (e.g. an enclosure or stator disc in a CAD session) into an outline polygon for `place_components`. For motors, plan the winding first with `winding_layout` (slots + poles \u2192 per-coil phase/polarity/winding-factor, as data \u2014 it touches no board), then realize it with `add_coil_array`. `run_drc` returns a summary by default (counts by rule + net-pair, worst clearance, a capped sample); pass `detail:'full'` for every violation. Surgical copper edits: `get_copper` lists existing traces/vias/zones (filtered by layer/net/bbox/kind) with the same indices `delete_trace`/`delete_via`/`delete_zone` accept \u2014 discover, then delete, without exporting the document. Where two nets must touch on purpose (wye neutral, split ground, shunt tap), declare it with `add_net_tie` \u2014 prefer a region-scoped tie (position+radius) so DRC stays honest away from the junction; `delete_net_tie` takes it back."
79928
79997
  ].join("\n");
79929
- if (!kernelPrompt) return header;
79998
+ if (!kernelPrompt) return header2;
79930
79999
  const sections = /* @__PURE__ */ new Map();
79931
80000
  for (const part of kernelPrompt.split(/^## /m).slice(1)) {
79932
80001
  const nl = part.indexOf("\n");
@@ -79937,7 +80006,7 @@ function buildInstructions(kernelPrompt) {
79937
80006
  (t2) => `## ${t2}
79938
80007
  ${sections.get(t2)}`
79939
80008
  );
79940
- return [header, ...picked].join("\n\n");
80009
+ return [header2, ...picked].join("\n\n");
79941
80010
  }
79942
80011
  function parseEnvPacks() {
79943
80012
  const env = process.env.VCAD_MCP_PACKS?.trim();
@@ -80373,7 +80442,7 @@ async function createServer(existingEngine, context = { user: null }) {
80373
80442
  ]
80374
80443
  };
80375
80444
  }
80376
- throw new Error(`Unknown resource: ${uri}`);
80445
+ throw new McpError(ErrorCode.InvalidParams, `Unknown resource: ${uri}`);
80377
80446
  });
80378
80447
  const clientHasInlineUi = () => {
80379
80448
  const caps = server.getClientCapabilities();
@@ -80787,8 +80856,8 @@ var init_server3 = __esm({
80787
80856
  init_order_feed();
80788
80857
  init_animate();
80789
80858
  PKG_VERSION = (() => {
80790
- if ("0.9.4-main.47") {
80791
- return "0.9.4-main.47";
80859
+ if ("0.9.4-main.48") {
80860
+ return "0.9.4-main.48";
80792
80861
  }
80793
80862
  try {
80794
80863
  const req = createRequire2(import.meta.url);
@@ -80797,8 +80866,8 @@ var init_server3 = __esm({
80797
80866
  return "0.0.0";
80798
80867
  }
80799
80868
  })();
80800
- BUILD_SHA = "e8c30217ef94fd492ae13caee599b581d8334d34";
80801
- BUILD_TIME = "2026-07-26T17:13:18.437Z";
80869
+ BUILD_SHA = "fe62ea0789005cd4b3f00777274323698634167d";
80870
+ BUILD_TIME = "2026-07-29T16:12:24.504Z";
80802
80871
  SHORT_SHA = BUILD_SHA === "unknown" ? "unknown" : BUILD_SHA.slice(0, 7);
80803
80872
  VERSION_WITH_BUILD = SHORT_SHA === "unknown" ? PKG_VERSION : `${PKG_VERSION}+${SHORT_SHA}`;
80804
80873
  INSTANCE_ID = randomUUID6().slice(0, 8);
@@ -81097,18 +81166,740 @@ var init_server3 = __esm({
81097
81166
  }
81098
81167
  });
81099
81168
 
81169
+ // node_modules/@modelcontextprotocol/sdk/dist/esm/inMemory.js
81170
+ var InMemoryTransport;
81171
+ var init_inMemory = __esm({
81172
+ "node_modules/@modelcontextprotocol/sdk/dist/esm/inMemory.js"() {
81173
+ InMemoryTransport = class _InMemoryTransport {
81174
+ constructor() {
81175
+ this._messageQueue = [];
81176
+ }
81177
+ /**
81178
+ * Creates a pair of linked in-memory transports that can communicate with each other. One should be passed to a Client and one to a Server.
81179
+ */
81180
+ static createLinkedPair() {
81181
+ const clientTransport = new _InMemoryTransport();
81182
+ const serverTransport = new _InMemoryTransport();
81183
+ clientTransport._otherTransport = serverTransport;
81184
+ serverTransport._otherTransport = clientTransport;
81185
+ return [clientTransport, serverTransport];
81186
+ }
81187
+ async start() {
81188
+ while (this._messageQueue.length > 0) {
81189
+ const queuedMessage = this._messageQueue.shift();
81190
+ this.onmessage?.(queuedMessage.message, queuedMessage.extra);
81191
+ }
81192
+ }
81193
+ async close() {
81194
+ const other = this._otherTransport;
81195
+ this._otherTransport = void 0;
81196
+ await other?.close();
81197
+ this.onclose?.();
81198
+ }
81199
+ /**
81200
+ * Sends a message with optional auth info.
81201
+ * This is useful for testing authentication scenarios.
81202
+ */
81203
+ async send(message, options) {
81204
+ if (!this._otherTransport) {
81205
+ throw new Error("Not connected");
81206
+ }
81207
+ if (this._otherTransport.onmessage) {
81208
+ this._otherTransport.onmessage(message, { authInfo: options?.authInfo });
81209
+ } else {
81210
+ this._otherTransport._messageQueue.push({ message, extra: { authInfo: options?.authInfo } });
81211
+ }
81212
+ }
81213
+ };
81214
+ }
81215
+ });
81216
+
81217
+ // src/protocol-2026.ts
81218
+ import { EventEmitter } from "node:events";
81219
+ import { randomUUID as randomUUID7 } from "node:crypto";
81220
+ function header(headers, name) {
81221
+ if (!headers) return void 0;
81222
+ const lower = name.toLowerCase();
81223
+ for (const [k, v] of Object.entries(headers)) {
81224
+ if (k.toLowerCase() !== lower) continue;
81225
+ return Array.isArray(v) ? v[0] : v;
81226
+ }
81227
+ return void 0;
81228
+ }
81229
+ function metaOf(msg) {
81230
+ const params = msg?.params;
81231
+ const meta = params?._meta;
81232
+ return meta && typeof meta === "object" ? meta : void 0;
81233
+ }
81234
+ function isModernMessage(msg, headers) {
81235
+ const first = Array.isArray(msg) ? msg[0] : msg;
81236
+ if (!first || typeof first !== "object") return false;
81237
+ const method = first.method;
81238
+ if (typeof method === "string" && MODERN_ONLY_METHODS.has(method)) return true;
81239
+ const declared = metaOf(first)?.[META_PROTOCOL_VERSION];
81240
+ if (typeof declared === "string") return true;
81241
+ return header(headers, "mcp-method") !== void 0;
81242
+ }
81243
+ function decodeHeaderValue(value) {
81244
+ if (!value.startsWith(BASE64_SENTINEL_PREFIX) || !value.endsWith(BASE64_SENTINEL_SUFFIX) || value.length < BASE64_SENTINEL_PREFIX.length + BASE64_SENTINEL_SUFFIX.length) {
81245
+ return value;
81246
+ }
81247
+ const encoded = value.slice(
81248
+ BASE64_SENTINEL_PREFIX.length,
81249
+ value.length - BASE64_SENTINEL_SUFFIX.length
81250
+ );
81251
+ try {
81252
+ return Buffer.from(encoded, "base64").toString("utf-8");
81253
+ } catch {
81254
+ return value;
81255
+ }
81256
+ }
81257
+ function errorResponse(id, code, message, data) {
81258
+ return {
81259
+ jsonrpc: "2.0",
81260
+ id: id ?? null,
81261
+ error: data === void 0 ? { code, message } : { code, message, data }
81262
+ };
81263
+ }
81264
+ function unsupportedVersion(id, requested) {
81265
+ return {
81266
+ status: 400,
81267
+ body: errorResponse(
81268
+ id,
81269
+ ERR_UNSUPPORTED_PROTOCOL_VERSION,
81270
+ "Unsupported protocol version",
81271
+ { supported: SUPPORTED_PROTOCOL_VERSIONS2, requested }
81272
+ )
81273
+ };
81274
+ }
81275
+ function headerMismatch(id, message) {
81276
+ return {
81277
+ status: 400,
81278
+ body: errorResponse(id, ERR_HEADER_MISMATCH, `Header mismatch: ${message}`)
81279
+ };
81280
+ }
81281
+ function pruneTasks() {
81282
+ const now = Date.now();
81283
+ for (const [id, t2] of tasks) {
81284
+ if (t2.expiresAt <= now) {
81285
+ t2.dispose?.();
81286
+ tasks.delete(id);
81287
+ }
81288
+ }
81289
+ }
81290
+ function touchTask(t2, status, message) {
81291
+ if (status) t2.status = status;
81292
+ if (message !== void 0) t2.statusMessage = message;
81293
+ t2.lastUpdatedAt = (/* @__PURE__ */ new Date()).toISOString();
81294
+ bus.emit(EVT_TASK, detailedTask(t2));
81295
+ }
81296
+ function detailedTask(t2) {
81297
+ const base = {
81298
+ taskId: t2.taskId,
81299
+ status: t2.status,
81300
+ createdAt: t2.createdAt,
81301
+ lastUpdatedAt: t2.lastUpdatedAt,
81302
+ ttlMs: TASK_TTL_MS,
81303
+ pollIntervalMs: TASK_POLL_INTERVAL_MS
81304
+ };
81305
+ if (t2.statusMessage !== void 0) base.statusMessage = t2.statusMessage;
81306
+ if (t2.status === "input_required") base.inputRequests = t2.inputRequests;
81307
+ if (t2.status === "completed") base.result = t2.result ?? {};
81308
+ if (t2.status === "failed") base.error = t2.error ?? { code: ERR_INTERNAL, message: "unknown" };
81309
+ return base;
81310
+ }
81311
+ async function openBridge(createServer2, clientInfo, clientCapabilities, hooks) {
81312
+ const [clientSide, serverSide] = InMemoryTransport.createLinkedPair();
81313
+ let nextId3 = 1;
81314
+ const pending2 = /* @__PURE__ */ new Map();
81315
+ clientSide.onmessage = (msg) => {
81316
+ const m = msg;
81317
+ const id = m.id;
81318
+ if (id !== void 0 && ("result" in m || "error" in m)) {
81319
+ pending2.get(id)?.(m);
81320
+ pending2.delete(id);
81321
+ return;
81322
+ }
81323
+ if (id !== void 0 && typeof m.method === "string") {
81324
+ void hooks.onServerRequest(
81325
+ m.method,
81326
+ m.params ?? {}
81327
+ ).then(
81328
+ (result) => clientSide.send({ jsonrpc: "2.0", id, result })
81329
+ ).catch(
81330
+ () => clientSide.send({
81331
+ jsonrpc: "2.0",
81332
+ id,
81333
+ error: { code: ERR_INTERNAL, message: "input bridge failed" }
81334
+ })
81335
+ );
81336
+ return;
81337
+ }
81338
+ if (typeof m.method === "string" && id === void 0) {
81339
+ hooks.onNotification?.(m);
81340
+ }
81341
+ };
81342
+ await clientSide.start();
81343
+ const server = await createServer2();
81344
+ await server.connect(serverSide);
81345
+ const rpc = (method, params) => {
81346
+ const id = nextId3++;
81347
+ return new Promise((resolve5) => {
81348
+ pending2.set(id, (m) => resolve5(m));
81349
+ void clientSide.send({
81350
+ jsonrpc: "2.0",
81351
+ id,
81352
+ method,
81353
+ params: params ?? {}
81354
+ });
81355
+ });
81356
+ };
81357
+ const init2 = await rpc("initialize", {
81358
+ protocolVersion: BRIDGE_VERSION,
81359
+ capabilities: clientCapabilities,
81360
+ clientInfo
81361
+ });
81362
+ await clientSide.send({
81363
+ jsonrpc: "2.0",
81364
+ method: "notifications/initialized"
81365
+ });
81366
+ return {
81367
+ rpc,
81368
+ handshake: init2.result ?? {},
81369
+ close: async () => {
81370
+ pending2.clear();
81371
+ await server.close().catch(() => {
81372
+ });
81373
+ await clientSide.close().catch(() => {
81374
+ });
81375
+ }
81376
+ };
81377
+ }
81378
+ async function handleModernRequest(msg, opts) {
81379
+ if (Array.isArray(msg)) {
81380
+ return {
81381
+ status: 400,
81382
+ body: errorResponse(
81383
+ null,
81384
+ ERR_INVALID_PARAMS,
81385
+ "Batched requests are not supported; send one JSON-RPC message per POST"
81386
+ )
81387
+ };
81388
+ }
81389
+ if (!msg || typeof msg !== "object") {
81390
+ return {
81391
+ status: 400,
81392
+ body: errorResponse(null, ERR_INVALID_PARAMS, "Malformed JSON-RPC message")
81393
+ };
81394
+ }
81395
+ const req = msg;
81396
+ const id = req.id;
81397
+ const method = req.method;
81398
+ const params = req.params ?? {};
81399
+ const meta = metaOf(req) ?? {};
81400
+ if (id === void 0 || id === null) return { status: 202, body: null };
81401
+ if (typeof method !== "string") {
81402
+ return {
81403
+ status: 400,
81404
+ body: errorResponse(id, ERR_INVALID_PARAMS, "Missing JSON-RPC method")
81405
+ };
81406
+ }
81407
+ const bodyVersion = meta[META_PROTOCOL_VERSION];
81408
+ const headerVersion = header(opts.headers, "mcp-protocol-version");
81409
+ if (typeof bodyVersion === "string" && headerVersion !== void 0 && headerVersion !== bodyVersion) {
81410
+ return headerMismatch(
81411
+ id,
81412
+ `MCP-Protocol-Version header value '${headerVersion}' does not match body value '${bodyVersion}'`
81413
+ );
81414
+ }
81415
+ const version2 = typeof bodyVersion === "string" ? bodyVersion : headerVersion;
81416
+ if (version2 === void 0) {
81417
+ if (method !== "server/discover") {
81418
+ return unsupportedVersion(id, "(unspecified)");
81419
+ }
81420
+ } else if (version2 !== PROTOCOL_2026) {
81421
+ return unsupportedVersion(id, version2);
81422
+ }
81423
+ if (opts.headers) {
81424
+ const methodHeader = header(opts.headers, "mcp-method");
81425
+ if (methodHeader === void 0) {
81426
+ return headerMismatch(id, "required header Mcp-Method is missing");
81427
+ }
81428
+ if (methodHeader !== method) {
81429
+ return headerMismatch(
81430
+ id,
81431
+ `Mcp-Method header value '${methodHeader}' does not match body value '${method}'`
81432
+ );
81433
+ }
81434
+ const expectedName = NAME_HEADER_METHODS.has(method) ? params.name : method === "resources/read" ? params.uri : void 0;
81435
+ if (typeof expectedName === "string") {
81436
+ const nameHeader = header(opts.headers, "mcp-name");
81437
+ if (nameHeader === void 0) {
81438
+ return headerMismatch(id, "required header Mcp-Name is missing");
81439
+ }
81440
+ if (decodeHeaderValue(nameHeader) !== expectedName) {
81441
+ return headerMismatch(
81442
+ id,
81443
+ `Mcp-Name header value does not match body value '${expectedName}'`
81444
+ );
81445
+ }
81446
+ }
81447
+ }
81448
+ if (method === "tasks/get" || method === "tasks/update" || method === "tasks/cancel") {
81449
+ return handleTaskMethod(id, method, params);
81450
+ }
81451
+ if (method === "initialize") {
81452
+ return {
81453
+ status: 404,
81454
+ body: errorResponse(
81455
+ id,
81456
+ ERR_METHOD_NOT_FOUND,
81457
+ `'initialize' was removed in protocol ${PROTOCOL_2026}; use 'server/discover'. This server supports: ${SUPPORTED_PROTOCOL_VERSIONS2.join(", ")}`
81458
+ )
81459
+ };
81460
+ }
81461
+ if (method !== "server/discover" && !FORWARDED_METHODS.has(method)) {
81462
+ return {
81463
+ status: 404,
81464
+ body: errorResponse(id, ERR_METHOD_NOT_FOUND, `Unknown method '${method}'`)
81465
+ };
81466
+ }
81467
+ const rawClientInfo = meta[META_CLIENT_INFO];
81468
+ const infoObj = rawClientInfo && typeof rawClientInfo === "object" ? rawClientInfo : {};
81469
+ const clientInfo = {
81470
+ name: typeof infoObj.name === "string" ? infoObj.name : "unknown",
81471
+ version: typeof infoObj.version === "string" ? infoObj.version : "0.0.0"
81472
+ };
81473
+ const rawCaps = meta[META_CLIENT_CAPABILITIES];
81474
+ const clientCapabilities = rawCaps && typeof rawCaps === "object" ? rawCaps : {};
81475
+ const wantsLogs = typeof meta[META_LOG_LEVEL] === "string";
81476
+ const inputResponses = params.inputResponses && typeof params.inputResponses === "object" ? params.inputResponses : {};
81477
+ const extCaps = clientCapabilities.extensions ?? {};
81478
+ const asTask = method === "tools/call" && TASKS_EXTENSION in extCaps && typeof params.name === "string" && LONG_RUNNING_TOOLS.has(params.name);
81479
+ let inputSeq = 0;
81480
+ const capturedInputRequests = {};
81481
+ const onServerRequest = async (reqMethod, reqParams) => {
81482
+ if (reqMethod !== "elicitation/create") {
81483
+ throw new Error(`unsupported server-initiated request ${reqMethod}`);
81484
+ }
81485
+ if (bridgeRef) {
81486
+ const parked = taskElicitation(bridgeRef, reqParams);
81487
+ if (parked) return parked;
81488
+ }
81489
+ const key = `input_${++inputSeq}`;
81490
+ const provided = inputResponses[key];
81491
+ if (provided) return provided;
81492
+ if (!MRTR_METHODS.has(method)) return { action: "cancel" };
81493
+ const { elicitationId: _drop, ...cleanParams } = reqParams;
81494
+ capturedInputRequests[key] = {
81495
+ method: "elicitation/create",
81496
+ params: cleanParams
81497
+ };
81498
+ return { action: "cancel" };
81499
+ };
81500
+ let bridge;
81501
+ let bridgeRef;
81502
+ try {
81503
+ bridge = bridgeRef = await openBridge(opts.createServer, clientInfo, clientCapabilities, {
81504
+ onNotification: (n) => {
81505
+ const nm = n.method;
81506
+ if (nm === "notifications/message" && !wantsLogs) return;
81507
+ opts.onNotification?.(n);
81508
+ },
81509
+ onServerRequest
81510
+ });
81511
+ if (method === "server/discover") {
81512
+ const info = bridge.handshake;
81513
+ const capabilities = { ...info.capabilities ?? {} };
81514
+ capabilities.extensions = {
81515
+ ...capabilities.extensions ?? {},
81516
+ [TASKS_EXTENSION]: {}
81517
+ };
81518
+ const result2 = {
81519
+ resultType: "complete",
81520
+ supportedVersions: SUPPORTED_PROTOCOL_VERSIONS2,
81521
+ capabilities,
81522
+ _meta: { [META_SERVER_INFO]: info.serverInfo ?? {} }
81523
+ };
81524
+ if (info.instructions) result2.instructions = info.instructions;
81525
+ decorateCache(result2, "server/discover");
81526
+ return { status: 200, body: { jsonrpc: "2.0", id, result: result2 } };
81527
+ }
81528
+ const serverInfo = bridge.handshake.serverInfo ?? {
81529
+ name: "vcad",
81530
+ version: "0.0.0"
81531
+ };
81532
+ const forwarded = stripModernFields(params);
81533
+ if (asTask) {
81534
+ pruneTasks();
81535
+ const record2 = createTaskRecord(params.name);
81536
+ const owned = bridge;
81537
+ bridge = void 0;
81538
+ runTaskInBackground(record2, owned, method, forwarded, inputResponses);
81539
+ const result2 = {
81540
+ resultType: "task",
81541
+ ...detailedTask(record2),
81542
+ _meta: { [META_SERVER_INFO]: serverInfo }
81543
+ };
81544
+ return { status: 200, body: { jsonrpc: "2.0", id, result: result2 } };
81545
+ }
81546
+ const reply = await bridge.rpc(method, forwarded);
81547
+ if (Object.keys(capturedInputRequests).length > 0) {
81548
+ const result2 = {
81549
+ resultType: "input_required",
81550
+ inputRequests: capturedInputRequests,
81551
+ _meta: { [META_SERVER_INFO]: serverInfo }
81552
+ };
81553
+ return { status: 200, body: { jsonrpc: "2.0", id, result: result2 } };
81554
+ }
81555
+ if (reply.error) {
81556
+ const code = reply.error.code === LEGACY_RESOURCE_NOT_FOUND ? ERR_INVALID_PARAMS : reply.error.code;
81557
+ return {
81558
+ status: code === ERR_METHOD_NOT_FOUND ? 404 : 200,
81559
+ body: errorResponse(id, code, reply.error.message, reply.error.data)
81560
+ };
81561
+ }
81562
+ const result = { ...reply.result ?? {} };
81563
+ result.resultType = "complete";
81564
+ const resultMeta = result._meta && typeof result._meta === "object" ? { ...result._meta } : {};
81565
+ resultMeta[META_SERVER_INFO] = serverInfo;
81566
+ result._meta = resultMeta;
81567
+ decorateCache(result, method);
81568
+ if (method === "tools/call" && params.name === "set_tool_packs") {
81569
+ bus.emit(EVT_TOOLS_CHANGED);
81570
+ }
81571
+ return { status: 200, body: { jsonrpc: "2.0", id, result } };
81572
+ } catch (err7) {
81573
+ return {
81574
+ status: 500,
81575
+ body: errorResponse(
81576
+ id,
81577
+ ERR_INTERNAL,
81578
+ err7 instanceof Error ? err7.message : String(err7)
81579
+ )
81580
+ };
81581
+ } finally {
81582
+ await bridge?.close();
81583
+ }
81584
+ }
81585
+ function decorateCache(result, method) {
81586
+ const ttl = CACHEABLE_METHODS.get(method);
81587
+ if (ttl === void 0) return;
81588
+ result.ttlMs = ttl;
81589
+ result.cacheScope = CACHE_SCOPE;
81590
+ }
81591
+ function stripModernFields(params) {
81592
+ const out = { ...params };
81593
+ delete out.inputResponses;
81594
+ delete out.requestState;
81595
+ const meta = out._meta;
81596
+ if (meta && typeof meta === "object") {
81597
+ const rest = { ...meta };
81598
+ delete rest[META_PROTOCOL_VERSION];
81599
+ delete rest[META_CLIENT_CAPABILITIES];
81600
+ delete rest[META_CLIENT_INFO];
81601
+ delete rest[META_LOG_LEVEL];
81602
+ if (Object.keys(rest).length === 0) delete out._meta;
81603
+ else out._meta = rest;
81604
+ }
81605
+ return out;
81606
+ }
81607
+ function createTaskRecord(toolName) {
81608
+ const now = (/* @__PURE__ */ new Date()).toISOString();
81609
+ const record2 = {
81610
+ taskId: `task_${randomUUID7().slice(0, 13)}`,
81611
+ status: "working",
81612
+ statusMessage: `running ${toolName}`,
81613
+ createdAt: now,
81614
+ lastUpdatedAt: now,
81615
+ expiresAt: Date.now() + TASK_TTL_MS,
81616
+ toolName,
81617
+ inputRequests: {},
81618
+ pendingInputs: /* @__PURE__ */ new Map(),
81619
+ cancelRequested: false
81620
+ };
81621
+ tasks.set(record2.taskId, record2);
81622
+ return record2;
81623
+ }
81624
+ function runTaskInBackground(record2, bridge, method, forwarded, presetResponses) {
81625
+ record2.dispose = () => {
81626
+ void bridge.close();
81627
+ };
81628
+ taskInputHooks.set(bridge, { record: record2, presetResponses, seq: 0 });
81629
+ void bridge.rpc(method, forwarded).then((reply) => {
81630
+ if (record2.status === "cancelled") return;
81631
+ if (reply.error) {
81632
+ record2.error = reply.error;
81633
+ touchTask(record2, "failed", reply.error.message);
81634
+ } else {
81635
+ const result = { ...reply.result ?? {} };
81636
+ result.resultType = "complete";
81637
+ record2.result = result;
81638
+ touchTask(record2, "completed", `${record2.toolName} finished`);
81639
+ }
81640
+ }).catch((err7) => {
81641
+ record2.error = {
81642
+ code: ERR_INTERNAL,
81643
+ message: err7 instanceof Error ? err7.message : String(err7)
81644
+ };
81645
+ touchTask(record2, "failed");
81646
+ }).finally(() => {
81647
+ taskInputHooks.delete(bridge);
81648
+ void bridge.close();
81649
+ record2.dispose = void 0;
81650
+ });
81651
+ }
81652
+ function taskElicitation(bridge, reqParams) {
81653
+ const ctx = taskInputHooks.get(bridge);
81654
+ if (!ctx) return void 0;
81655
+ const { record: record2, presetResponses } = ctx;
81656
+ const key = `input_${++ctx.seq}`;
81657
+ const preset = presetResponses[key];
81658
+ if (preset) return Promise.resolve(preset);
81659
+ if (record2.cancelRequested) return Promise.resolve({ action: "cancel" });
81660
+ const { elicitationId: _drop, ...cleanParams } = reqParams;
81661
+ record2.inputRequests[key] = {
81662
+ method: "elicitation/create",
81663
+ params: cleanParams
81664
+ };
81665
+ return new Promise((resolve5) => {
81666
+ record2.pendingInputs.set(key, resolve5);
81667
+ touchTask(record2, "input_required", "waiting for client input");
81668
+ });
81669
+ }
81670
+ function handleTaskMethod(id, method, params) {
81671
+ pruneTasks();
81672
+ const taskId = typeof params.taskId === "string" ? params.taskId : "";
81673
+ const record2 = tasks.get(taskId);
81674
+ if (!record2) {
81675
+ return {
81676
+ status: 200,
81677
+ body: errorResponse(
81678
+ id,
81679
+ ERR_INVALID_PARAMS,
81680
+ `Unknown taskId '${taskId}' \u2014 expired, cancelled long ago, or from a previous server instance`
81681
+ )
81682
+ };
81683
+ }
81684
+ if (method === "tasks/get") {
81685
+ const result = { resultType: "complete", ...detailedTask(record2) };
81686
+ return { status: 200, body: { jsonrpc: "2.0", id, result } };
81687
+ }
81688
+ if (method === "tasks/update") {
81689
+ const responses = params.inputResponses && typeof params.inputResponses === "object" ? params.inputResponses : {};
81690
+ for (const [key, response] of Object.entries(responses)) {
81691
+ const resolve5 = record2.pendingInputs.get(key);
81692
+ if (!resolve5) continue;
81693
+ record2.pendingInputs.delete(key);
81694
+ delete record2.inputRequests[key];
81695
+ resolve5(response);
81696
+ }
81697
+ if (record2.status === "input_required" && Object.keys(record2.inputRequests).length === 0) {
81698
+ touchTask(record2, "working", `running ${record2.toolName}`);
81699
+ }
81700
+ return {
81701
+ status: 200,
81702
+ body: { jsonrpc: "2.0", id, result: { resultType: "complete" } }
81703
+ };
81704
+ }
81705
+ record2.cancelRequested = true;
81706
+ if (record2.status === "working" || record2.status === "input_required") {
81707
+ for (const [key, resolve5] of record2.pendingInputs) {
81708
+ record2.pendingInputs.delete(key);
81709
+ delete record2.inputRequests[key];
81710
+ resolve5({ action: "cancel" });
81711
+ }
81712
+ touchTask(record2, "cancelled", "cancelled by client");
81713
+ }
81714
+ return {
81715
+ status: 200,
81716
+ body: { jsonrpc: "2.0", id, result: { resultType: "complete" } }
81717
+ };
81718
+ }
81719
+ function handleModernListen(msg, sink) {
81720
+ const req = msg;
81721
+ const subscriptionId = req.id ?? null;
81722
+ const filter = req.params?.notifications && typeof req.params.notifications === "object" ? req.params.notifications : {};
81723
+ const honored = {};
81724
+ const listeners = [];
81725
+ if (filter.toolsListChanged === true) {
81726
+ honored.toolsListChanged = true;
81727
+ const onChange = () => sink.send({
81728
+ jsonrpc: "2.0",
81729
+ method: "notifications/tools/list_changed",
81730
+ params: { _meta: { [META_SUBSCRIPTION_ID]: subscriptionId } }
81731
+ });
81732
+ bus.on(EVT_TOOLS_CHANGED, onChange);
81733
+ listeners.push(() => bus.off(EVT_TOOLS_CHANGED, onChange));
81734
+ }
81735
+ const taskIds = Array.isArray(filter.taskIds) ? filter.taskIds.filter((t2) => typeof t2 === "string") : [];
81736
+ if (taskIds.length > 0) {
81737
+ honored.taskIds = taskIds;
81738
+ const wanted = new Set(taskIds);
81739
+ const onTask = (task) => {
81740
+ if (!wanted.has(task.taskId)) return;
81741
+ sink.send({
81742
+ jsonrpc: "2.0",
81743
+ method: "notifications/tasks",
81744
+ params: { _meta: { [META_SUBSCRIPTION_ID]: subscriptionId }, ...task }
81745
+ });
81746
+ };
81747
+ bus.on(EVT_TASK, onTask);
81748
+ listeners.push(() => bus.off(EVT_TASK, onTask));
81749
+ }
81750
+ sink.send({
81751
+ jsonrpc: "2.0",
81752
+ method: "notifications/subscriptions/acknowledged",
81753
+ params: {
81754
+ _meta: { [META_SUBSCRIPTION_ID]: subscriptionId },
81755
+ notifications: honored
81756
+ }
81757
+ });
81758
+ return {
81759
+ close: () => {
81760
+ for (const off of listeners) off();
81761
+ listeners.length = 0;
81762
+ }
81763
+ };
81764
+ }
81765
+ 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;
81766
+ var init_protocol_2026 = __esm({
81767
+ "src/protocol-2026.ts"() {
81768
+ "use strict";
81769
+ init_inMemory();
81770
+ PROTOCOL_2026 = "2026-07-28";
81771
+ BRIDGE_VERSION = "2025-11-25";
81772
+ SUPPORTED_PROTOCOL_VERSIONS2 = [
81773
+ PROTOCOL_2026,
81774
+ "2025-11-25",
81775
+ "2025-06-18",
81776
+ "2025-03-26",
81777
+ "2024-11-05"
81778
+ ];
81779
+ META_PROTOCOL_VERSION = "io.modelcontextprotocol/protocolVersion";
81780
+ META_CLIENT_CAPABILITIES = "io.modelcontextprotocol/clientCapabilities";
81781
+ META_CLIENT_INFO = "io.modelcontextprotocol/clientInfo";
81782
+ META_SERVER_INFO = "io.modelcontextprotocol/serverInfo";
81783
+ META_LOG_LEVEL = "io.modelcontextprotocol/logLevel";
81784
+ META_SUBSCRIPTION_ID = "io.modelcontextprotocol/subscriptionId";
81785
+ TASKS_EXTENSION = "io.modelcontextprotocol/tasks";
81786
+ ERR_HEADER_MISMATCH = -32020;
81787
+ ERR_UNSUPPORTED_PROTOCOL_VERSION = -32022;
81788
+ ERR_METHOD_NOT_FOUND = -32601;
81789
+ ERR_INVALID_PARAMS = -32602;
81790
+ ERR_INTERNAL = -32603;
81791
+ LEGACY_RESOURCE_NOT_FOUND = -32002;
81792
+ LIST_TTL_MS = 6e4;
81793
+ DISCOVER_TTL_MS = 3e5;
81794
+ CACHE_SCOPE = "private";
81795
+ CACHEABLE_METHODS = /* @__PURE__ */ new Map([
81796
+ ["server/discover", DISCOVER_TTL_MS],
81797
+ ["tools/list", LIST_TTL_MS],
81798
+ ["prompts/list", LIST_TTL_MS],
81799
+ ["resources/list", LIST_TTL_MS],
81800
+ ["resources/templates/list", LIST_TTL_MS],
81801
+ ["resources/read", LIST_TTL_MS]
81802
+ ]);
81803
+ FORWARDED_METHODS = /* @__PURE__ */ new Set([
81804
+ "tools/list",
81805
+ "tools/call",
81806
+ "resources/list",
81807
+ "resources/templates/list",
81808
+ "resources/read",
81809
+ "prompts/list",
81810
+ "prompts/get",
81811
+ "completion/complete"
81812
+ ]);
81813
+ NAME_HEADER_METHODS = /* @__PURE__ */ new Set(["tools/call", "prompts/get"]);
81814
+ MRTR_METHODS = /* @__PURE__ */ new Set(["tools/call", "prompts/get", "resources/read"]);
81815
+ LONG_RUNNING_TOOLS = /* @__PURE__ */ new Set([
81816
+ "route_nets",
81817
+ "route_diff_pair",
81818
+ "length_match_traces",
81819
+ "fab_prep",
81820
+ "fix_drc",
81821
+ "topology_optimize",
81822
+ "optimize_electrodes",
81823
+ "export_video",
81824
+ "render_sequence",
81825
+ "simulate_flow",
81826
+ "simulate_em",
81827
+ "simulate_photonics",
81828
+ "simulate_charged_particles",
81829
+ "simulate_neutron_shield",
81830
+ "simulate_lattice_gauge",
81831
+ "md_run",
81832
+ "minimize_energy",
81833
+ "homogenize_material",
81834
+ "design_material"
81835
+ ]);
81836
+ TASK_TTL_MS = 30 * 6e4;
81837
+ TASK_POLL_INTERVAL_MS = 1e3;
81838
+ MODERN_ONLY_METHODS = /* @__PURE__ */ new Set([
81839
+ "server/discover",
81840
+ "subscriptions/listen",
81841
+ "tasks/get",
81842
+ "tasks/update",
81843
+ "tasks/cancel"
81844
+ ]);
81845
+ BASE64_SENTINEL_PREFIX = "=?base64?";
81846
+ BASE64_SENTINEL_SUFFIX = "?=";
81847
+ bus = new EventEmitter();
81848
+ bus.setMaxListeners(100);
81849
+ EVT_TOOLS_CHANGED = "tools_list_changed";
81850
+ EVT_TASK = "task";
81851
+ tasks = /* @__PURE__ */ new Map();
81852
+ taskInputHooks = /* @__PURE__ */ new WeakMap();
81853
+ }
81854
+ });
81855
+
81100
81856
  // src/index.ts
81101
81857
  var index_exports = {};
81102
81858
  async function main() {
81103
81859
  const server = await createServer(void 0, { user: null });
81104
81860
  const transport = new StdioServerTransport();
81105
81861
  await server.connect(transport);
81862
+ const legacyOnMessage = transport.onmessage?.bind(transport);
81863
+ const listens = /* @__PURE__ */ new Map();
81864
+ transport.onmessage = (msg) => {
81865
+ if (!isModernMessage(msg)) {
81866
+ const m = msg;
81867
+ const cancelId = m.params?.requestId;
81868
+ if (m.method === "notifications/cancelled" && cancelId !== void 0 && listens.has(cancelId)) {
81869
+ listens.get(cancelId).close();
81870
+ listens.delete(cancelId);
81871
+ return;
81872
+ }
81873
+ legacyOnMessage?.(msg);
81874
+ return;
81875
+ }
81876
+ const method = msg.method;
81877
+ if (method === "subscriptions/listen") {
81878
+ const id = msg.id;
81879
+ const handle = handleModernListen(msg, {
81880
+ send: (m) => void transport.send(m)
81881
+ });
81882
+ if (id !== void 0) listens.set(id, handle);
81883
+ return;
81884
+ }
81885
+ void handleModernRequest(msg, {
81886
+ createServer: () => createServer(void 0, { user: null }),
81887
+ // Request-scoped notifications share the stdio channel; the SDK
81888
+ // client correlates progress via its progressToken.
81889
+ onNotification: (n) => void transport.send(n)
81890
+ }).then(({ body }) => {
81891
+ if (body !== null) {
81892
+ void transport.send(body);
81893
+ }
81894
+ });
81895
+ };
81106
81896
  }
81107
81897
  var init_index = __esm({
81108
81898
  "src/index.ts"() {
81109
81899
  "use strict";
81110
81900
  init_stdio2();
81111
81901
  init_server3();
81902
+ init_protocol_2026();
81112
81903
  console.log = (...args) => console.error(...args);
81113
81904
  main().catch((err7) => {
81114
81905
  console.error("Fatal error:", err7);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vcad/mcp",
3
- "version": "0.9.4-main.47",
3
+ "version": "0.9.4-main.48",
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": "e8c30217ef94fd492ae13caee599b581d8334d34",
23
- "builtAt": "2026-07-26T17:13:18.437Z"
22
+ "sha": "fe62ea0789005cd4b3f00777274323698634167d",
23
+ "builtAt": "2026-07-29T16:12:24.504Z"
24
24
  }
25
25
  }
Binary file