@vcad/mcp 0.9.4-main.46 → 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 +1 -1
- package/index.mjs +849 -54
- package/package.json +3 -3
- package/vcad_kernel_wasm_bg.wasm +0 -0
package/README.md
CHANGED
|
@@ -6,4 +6,4 @@ vcad's MCP server as a self-contained bundle (server + BRep kernel WASM).
|
|
|
6
6
|
{ "mcpServers": { "vcad": { "command": "npx", "args": ["-y", "@vcad/mcp"] } } }
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
Built from
|
|
9
|
+
Built from 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 [
|
|
13737
|
-
if (!
|
|
13765
|
+
const [header2] = tokensParts;
|
|
13766
|
+
if (!header2)
|
|
13738
13767
|
return false;
|
|
13739
|
-
const parsedHeader = JSON.parse(atob(
|
|
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
|
|
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:
|
|
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(
|
|
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
|
|
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:
|
|
18933
|
+
message: errorResponse2,
|
|
18905
18934
|
timestamp: Date.now()
|
|
18906
18935
|
}, capturedTransport?.sessionId);
|
|
18907
18936
|
} else {
|
|
18908
|
-
await capturedTransport?.send(
|
|
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) {
|
|
@@ -30247,11 +30276,6 @@ var init_ui_store = __esm({
|
|
|
30247
30276
|
raytraceEdgeCreaseWidth: 0.75,
|
|
30248
30277
|
raytraceEdgeBoundaryWidth: 1.25,
|
|
30249
30278
|
raytraceEdgeSoftness: 1.5,
|
|
30250
|
-
raytraceAoEnabled: true,
|
|
30251
|
-
raytraceAoRadius: 0.3,
|
|
30252
|
-
raytraceAoIntensity: 1,
|
|
30253
|
-
raytraceAoBias: 1e-3,
|
|
30254
|
-
raytraceAoSampleCount: 16,
|
|
30255
30279
|
toolbarExpanded: persistedToolbarExpanded,
|
|
30256
30280
|
toolbarTab: "create",
|
|
30257
30281
|
sidebarPane: "tree",
|
|
@@ -30356,11 +30380,6 @@ var init_ui_store = __esm({
|
|
|
30356
30380
|
setRaytraceEdgeCreaseWidth: (width) => set({ raytraceEdgeCreaseWidth: width }),
|
|
30357
30381
|
setRaytraceEdgeBoundaryWidth: (width) => set({ raytraceEdgeBoundaryWidth: width }),
|
|
30358
30382
|
setRaytraceEdgeSoftness: (softness) => set({ raytraceEdgeSoftness: softness }),
|
|
30359
|
-
setRaytraceAoEnabled: (enabled) => set({ raytraceAoEnabled: enabled }),
|
|
30360
|
-
setRaytraceAoRadius: (radius) => set({ raytraceAoRadius: radius }),
|
|
30361
|
-
setRaytraceAoIntensity: (intensity) => set({ raytraceAoIntensity: intensity }),
|
|
30362
|
-
setRaytraceAoBias: (bias) => set({ raytraceAoBias: bias }),
|
|
30363
|
-
setRaytraceAoSampleCount: (count) => set({ raytraceAoSampleCount: count }),
|
|
30364
30383
|
setToolbarExpanded: (expanded) => {
|
|
30365
30384
|
try {
|
|
30366
30385
|
localStorage.setItem("vcad:toolbarExpanded", String(expanded));
|
|
@@ -41050,6 +41069,32 @@ var init_CHANGELOG = __esm({
|
|
|
41050
41069
|
CHANGELOG_default = {
|
|
41051
41070
|
$schema: "./changelog.schema.json",
|
|
41052
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
|
+
},
|
|
41084
|
+
{
|
|
41085
|
+
id: "2026-07-26-viewport-path-tracer",
|
|
41086
|
+
version: "0.9.4",
|
|
41087
|
+
date: "2026-07-26",
|
|
41088
|
+
category: "feat",
|
|
41089
|
+
title: "The raytrace viewport is a real path tracer",
|
|
41090
|
+
summary: "The viewport now shades with the same BSDF, materials and lighting as --photoreal: multi-bounce global illumination, MIS area lights, clearcoat and brushed-metal anisotropy, so a part looks the same in the app as in a render.",
|
|
41091
|
+
features: [
|
|
41092
|
+
"rendering",
|
|
41093
|
+
"raytracing",
|
|
41094
|
+
"viewport",
|
|
41095
|
+
"materials"
|
|
41096
|
+
]
|
|
41097
|
+
},
|
|
41053
41098
|
{
|
|
41054
41099
|
id: "2026-07-26-swept-and-all-pairs-clearance",
|
|
41055
41100
|
version: "0.9.4",
|
|
@@ -41069,6 +41114,21 @@ var init_CHANGELOG = __esm({
|
|
|
41069
41114
|
"verify_receipt"
|
|
41070
41115
|
]
|
|
41071
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
|
+
},
|
|
41072
41132
|
{
|
|
41073
41133
|
id: "2026-07-26-step-export-booleans",
|
|
41074
41134
|
version: "0.9.4",
|
|
@@ -41086,6 +41146,19 @@ var init_CHANGELOG = __esm({
|
|
|
41086
41146
|
"export_cad"
|
|
41087
41147
|
]
|
|
41088
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
|
+
},
|
|
41089
41162
|
{
|
|
41090
41163
|
id: "2026-07-26-render-loon-directly",
|
|
41091
41164
|
version: "0.9.4",
|
|
@@ -71085,7 +71158,7 @@ function listEvalTasks(args) {
|
|
|
71085
71158
|
}
|
|
71086
71159
|
const tasksDir = join3(mechevalRoot, "tasks");
|
|
71087
71160
|
const suiteFilter = args.suite ? String(args.suite).toUpperCase() : null;
|
|
71088
|
-
const
|
|
71161
|
+
const tasks2 = [];
|
|
71089
71162
|
for (const file of readdirSync2(tasksDir).sort()) {
|
|
71090
71163
|
if (!file.endsWith(".json")) continue;
|
|
71091
71164
|
try {
|
|
@@ -71093,7 +71166,7 @@ function listEvalTasks(args) {
|
|
|
71093
71166
|
if (suiteFilter && String(raw.suite).toUpperCase() !== suiteFilter) {
|
|
71094
71167
|
continue;
|
|
71095
71168
|
}
|
|
71096
|
-
|
|
71169
|
+
tasks2.push({
|
|
71097
71170
|
id: raw.id,
|
|
71098
71171
|
suite: raw.suite,
|
|
71099
71172
|
tier: raw.tier,
|
|
@@ -71105,7 +71178,7 @@ function listEvalTasks(args) {
|
|
|
71105
71178
|
} catch {
|
|
71106
71179
|
}
|
|
71107
71180
|
}
|
|
71108
|
-
return textResult({ count:
|
|
71181
|
+
return textResult({ count: tasks2.length, tasks: tasks2 });
|
|
71109
71182
|
}
|
|
71110
71183
|
async function verifyPart(args) {
|
|
71111
71184
|
const documentId = String(args.document_id ?? "");
|
|
@@ -79904,7 +79977,7 @@ function getBuildInfo() {
|
|
|
79904
79977
|
};
|
|
79905
79978
|
}
|
|
79906
79979
|
function buildInstructions(kernelPrompt) {
|
|
79907
|
-
const
|
|
79980
|
+
const header2 = [
|
|
79908
79981
|
"vcad \u2014 parametric CAD with a real BRep kernel. Coordinate system: Z-up (X right, Y forward, Z up). Units: millimeters.",
|
|
79909
79982
|
"",
|
|
79910
79983
|
"Workflow: `open_document` \u2192 author \u2192 see \u2192 measure \u2192 ship.",
|
|
@@ -79922,7 +79995,7 @@ function buildInstructions(kernelPrompt) {
|
|
|
79922
79995
|
"",
|
|
79923
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."
|
|
79924
79997
|
].join("\n");
|
|
79925
|
-
if (!kernelPrompt) return
|
|
79998
|
+
if (!kernelPrompt) return header2;
|
|
79926
79999
|
const sections = /* @__PURE__ */ new Map();
|
|
79927
80000
|
for (const part of kernelPrompt.split(/^## /m).slice(1)) {
|
|
79928
80001
|
const nl = part.indexOf("\n");
|
|
@@ -79933,7 +80006,7 @@ function buildInstructions(kernelPrompt) {
|
|
|
79933
80006
|
(t2) => `## ${t2}
|
|
79934
80007
|
${sections.get(t2)}`
|
|
79935
80008
|
);
|
|
79936
|
-
return [
|
|
80009
|
+
return [header2, ...picked].join("\n\n");
|
|
79937
80010
|
}
|
|
79938
80011
|
function parseEnvPacks() {
|
|
79939
80012
|
const env = process.env.VCAD_MCP_PACKS?.trim();
|
|
@@ -80369,7 +80442,7 @@ async function createServer(existingEngine, context = { user: null }) {
|
|
|
80369
80442
|
]
|
|
80370
80443
|
};
|
|
80371
80444
|
}
|
|
80372
|
-
throw new
|
|
80445
|
+
throw new McpError(ErrorCode.InvalidParams, `Unknown resource: ${uri}`);
|
|
80373
80446
|
});
|
|
80374
80447
|
const clientHasInlineUi = () => {
|
|
80375
80448
|
const caps = server.getClientCapabilities();
|
|
@@ -80783,8 +80856,8 @@ var init_server3 = __esm({
|
|
|
80783
80856
|
init_order_feed();
|
|
80784
80857
|
init_animate();
|
|
80785
80858
|
PKG_VERSION = (() => {
|
|
80786
|
-
if ("0.9.4-main.
|
|
80787
|
-
return "0.9.4-main.
|
|
80859
|
+
if ("0.9.4-main.48") {
|
|
80860
|
+
return "0.9.4-main.48";
|
|
80788
80861
|
}
|
|
80789
80862
|
try {
|
|
80790
80863
|
const req = createRequire2(import.meta.url);
|
|
@@ -80793,8 +80866,8 @@ var init_server3 = __esm({
|
|
|
80793
80866
|
return "0.0.0";
|
|
80794
80867
|
}
|
|
80795
80868
|
})();
|
|
80796
|
-
BUILD_SHA = "
|
|
80797
|
-
BUILD_TIME = "2026-07-
|
|
80869
|
+
BUILD_SHA = "fe62ea0789005cd4b3f00777274323698634167d";
|
|
80870
|
+
BUILD_TIME = "2026-07-29T16:12:24.504Z";
|
|
80798
80871
|
SHORT_SHA = BUILD_SHA === "unknown" ? "unknown" : BUILD_SHA.slice(0, 7);
|
|
80799
80872
|
VERSION_WITH_BUILD = SHORT_SHA === "unknown" ? PKG_VERSION : `${PKG_VERSION}+${SHORT_SHA}`;
|
|
80800
80873
|
INSTANCE_ID = randomUUID6().slice(0, 8);
|
|
@@ -81093,18 +81166,740 @@ var init_server3 = __esm({
|
|
|
81093
81166
|
}
|
|
81094
81167
|
});
|
|
81095
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
|
+
|
|
81096
81856
|
// src/index.ts
|
|
81097
81857
|
var index_exports = {};
|
|
81098
81858
|
async function main() {
|
|
81099
81859
|
const server = await createServer(void 0, { user: null });
|
|
81100
81860
|
const transport = new StdioServerTransport();
|
|
81101
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
|
+
};
|
|
81102
81896
|
}
|
|
81103
81897
|
var init_index = __esm({
|
|
81104
81898
|
"src/index.ts"() {
|
|
81105
81899
|
"use strict";
|
|
81106
81900
|
init_stdio2();
|
|
81107
81901
|
init_server3();
|
|
81902
|
+
init_protocol_2026();
|
|
81108
81903
|
console.log = (...args) => console.error(...args);
|
|
81109
81904
|
main().catch((err7) => {
|
|
81110
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.
|
|
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": "
|
|
23
|
-
"builtAt": "2026-07-
|
|
22
|
+
"sha": "fe62ea0789005cd4b3f00777274323698634167d",
|
|
23
|
+
"builtAt": "2026-07-29T16:12:24.504Z"
|
|
24
24
|
}
|
|
25
25
|
}
|
package/vcad_kernel_wasm_bg.wasm
CHANGED
|
Binary file
|