toolception 0.6.1 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +1 -1
  2. package/dist/core/DynamicToolManager.d.ts +33 -22
  3. package/dist/core/DynamicToolManager.d.ts.map +1 -1
  4. package/dist/core/ServerOrchestrator.d.ts +33 -25
  5. package/dist/core/ServerOrchestrator.d.ts.map +1 -1
  6. package/dist/core/ToolRegistry.d.ts +5 -3
  7. package/dist/core/ToolRegistry.d.ts.map +1 -1
  8. package/dist/core/core.types.d.ts +29 -0
  9. package/dist/core/core.types.d.ts.map +1 -0
  10. package/dist/http/FastifyTransport.d.ts +74 -41
  11. package/dist/http/FastifyTransport.d.ts.map +1 -1
  12. package/dist/http/{customEndpoints.d.ts → http.types.d.ts} +33 -86
  13. package/dist/http/http.types.d.ts.map +1 -0
  14. package/dist/http/http.utils.d.ts +121 -0
  15. package/dist/http/http.utils.d.ts.map +1 -0
  16. package/dist/index.d.ts +5 -5
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +1138 -870
  19. package/dist/index.js.map +1 -1
  20. package/dist/mode/ModeResolver.d.ts +11 -10
  21. package/dist/mode/ModeResolver.d.ts.map +1 -1
  22. package/dist/mode/ModuleResolver.d.ts +18 -4
  23. package/dist/mode/ModuleResolver.d.ts.map +1 -1
  24. package/dist/mode/mode.types.d.ts +15 -0
  25. package/dist/mode/mode.types.d.ts.map +1 -0
  26. package/dist/permissions/PermissionAwareFastifyTransport.d.ts +15 -39
  27. package/dist/permissions/PermissionAwareFastifyTransport.d.ts.map +1 -1
  28. package/dist/permissions/PermissionResolver.d.ts +9 -24
  29. package/dist/permissions/PermissionResolver.d.ts.map +1 -1
  30. package/dist/permissions/{createPermissionAwareBundle.d.ts → permissions.types.d.ts} +17 -18
  31. package/dist/permissions/permissions.types.d.ts.map +1 -0
  32. package/dist/permissions/permissions.utils.d.ts +31 -0
  33. package/dist/permissions/permissions.utils.d.ts.map +1 -0
  34. package/dist/server/createMcpServer.d.ts +3 -46
  35. package/dist/server/createMcpServer.d.ts.map +1 -1
  36. package/dist/server/createPermissionBasedMcpServer.d.ts +2 -64
  37. package/dist/server/createPermissionBasedMcpServer.d.ts.map +1 -1
  38. package/dist/server/server.types.d.ts +71 -0
  39. package/dist/server/server.types.d.ts.map +1 -0
  40. package/dist/server/server.utils.d.ts +45 -0
  41. package/dist/server/server.utils.d.ts.map +1 -0
  42. package/dist/session/ClientResourceCache.d.ts +8 -27
  43. package/dist/session/ClientResourceCache.d.ts.map +1 -1
  44. package/dist/session/SessionContextResolver.d.ts +21 -72
  45. package/dist/session/SessionContextResolver.d.ts.map +1 -1
  46. package/dist/session/session.types.d.ts +29 -0
  47. package/dist/session/session.types.d.ts.map +1 -0
  48. package/dist/session/{validateSessionContextConfig.d.ts → session.utils.d.ts} +1 -2
  49. package/dist/session/session.utils.d.ts.map +1 -0
  50. package/dist/types/index.d.ts +0 -24
  51. package/dist/types/index.d.ts.map +1 -1
  52. package/package.json +2 -2
  53. package/dist/http/customEndpoints.d.ts.map +0 -1
  54. package/dist/http/endpointRegistration.d.ts +0 -35
  55. package/dist/http/endpointRegistration.d.ts.map +0 -1
  56. package/dist/permissions/createPermissionAwareBundle.d.ts.map +0 -1
  57. package/dist/permissions/validatePermissionConfig.d.ts +0 -9
  58. package/dist/permissions/validatePermissionConfig.d.ts.map +0 -1
  59. package/dist/session/validateSessionContextConfig.d.ts.map +0 -1
package/dist/index.js CHANGED
@@ -1,70 +1,71 @@
1
- var re = Object.defineProperty;
2
- var j = (o) => {
3
- throw TypeError(o);
1
+ var ve = Object.defineProperty;
2
+ var H = (r) => {
3
+ throw TypeError(r);
4
4
  };
5
- var ie = (o, e, t) => e in o ? re(o, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : o[e] = t;
6
- var d = (o, e, t) => ie(o, typeof e != "symbol" ? e + "" : e, t), ne = (o, e, t) => e.has(o) || j("Cannot " + t);
7
- var A = (o, e, t) => e.has(o) ? j("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(o) : e.set(o, t);
8
- var m = (o, e, t) => (ne(o, e, "access private method"), t);
9
- import { z as v } from "zod";
10
- import N from "fastify";
11
- import D from "@fastify/cors";
12
- import { randomUUID as S, createHash as ae } from "node:crypto";
13
- import { StreamableHTTPServerTransport as z } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
14
- import { isInitializeRequest as _ } from "@modelcontextprotocol/sdk/types.js";
15
- const R = {
5
+ var be = (r, e, t) => e in r ? ve(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t;
6
+ var d = (r, e, t) => be(r, typeof e != "symbol" ? e + "" : e, t), we = (r, e, t) => e.has(r) || H("Cannot " + t);
7
+ var x = (r, e, t) => e.has(r) ? H("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(r) : e.set(r, t);
8
+ var m = (r, e, t) => (we(r, e, "access private method"), t);
9
+ import { z as g } from "zod";
10
+ import U from "fastify";
11
+ import J from "@fastify/cors";
12
+ import { randomUUID as S, createHash as Te } from "node:crypto";
13
+ import { StreamableHTTPServerTransport as Q } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
14
+ import { isInitializeRequest as G } from "@modelcontextprotocol/sdk/types.js";
15
+ const V = {
16
16
  dynamic: [
17
17
  "dynamic-tool-discovery",
18
18
  "dynamicToolDiscovery",
19
19
  "DYNAMIC_TOOL_DISCOVERY"
20
20
  ],
21
21
  toolsets: ["tool-sets", "toolSets", "FMP_TOOL_SETS"]
22
- };
23
- class le {
22
+ }, W = ["_meta"];
23
+ class L {
24
24
  constructor(e = {}) {
25
25
  d(this, "keys");
26
26
  this.keys = {
27
- dynamic: e.keys?.dynamic ?? R.dynamic,
28
- toolsets: e.keys?.toolsets ?? R.toolsets
27
+ dynamic: e.keys?.dynamic ?? V.dynamic,
28
+ toolsets: e.keys?.toolsets ?? V.toolsets
29
+ };
30
+ }
31
+ static builder() {
32
+ const e = {}, t = {
33
+ keys(s) {
34
+ return e.keys = s, t;
35
+ },
36
+ build() {
37
+ return new L(e);
38
+ }
29
39
  };
40
+ return t;
30
41
  }
31
42
  resolveMode(e, t) {
32
43
  return this.isDynamicEnabled(t) ? "DYNAMIC" : this.getToolsetsString(t) ? "STATIC" : this.isDynamicEnabled(e) ? "DYNAMIC" : this.getToolsetsString(e) ? "STATIC" : null;
33
44
  }
34
45
  parseCommaSeparatedToolSets(e, t) {
35
46
  if (!e || typeof e != "string") return [];
36
- const s = e.split(",").map((n) => n.trim()).filter((n) => n.length > 0), r = new Set(Object.keys(t)), i = [];
37
- for (const n of s)
38
- r.has(n) ? i.push(n) : console.warn(
39
- `Invalid toolset '${n}' ignored. Available: ${Array.from(
40
- r
47
+ const s = e.split(",").map((i) => i.trim()).filter((i) => i.length > 0), o = new Set(Object.keys(t)), n = [];
48
+ for (const i of s)
49
+ o.has(i) ? n.push(i) : console.warn(
50
+ `Invalid toolset '${i}' ignored. Available: ${Array.from(
51
+ o
41
52
  ).join(", ")}`
42
53
  );
43
- return i;
54
+ return n;
44
55
  }
45
56
  getModulesForToolSets(e, t) {
46
57
  const s = /* @__PURE__ */ new Set();
47
- for (const r of e) {
48
- const i = t[r];
49
- i && (i.modules || []).forEach((n) => s.add(n));
58
+ for (const o of e) {
59
+ const n = t[o];
60
+ n && (n.modules || []).forEach((i) => s.add(i));
50
61
  }
51
62
  return Array.from(s);
52
63
  }
53
64
  validateToolsetName(e, t) {
54
65
  if (!e || typeof e != "string")
55
- return {
56
- isValid: !1,
57
- error: `Invalid toolset name provided. Must be a non-empty string. Available toolsets: ${Object.keys(
58
- t
59
- ).join(", ")}`
60
- };
66
+ return this.createInvalidNameError(e, t);
61
67
  const s = e.trim();
62
- return s.length === 0 ? {
63
- isValid: !1,
64
- error: `Empty toolset name provided. Available toolsets: ${Object.keys(
65
- t
66
- ).join(", ")}`
67
- } : t[s] ? { isValid: !0, sanitized: s } : {
68
+ return s.length === 0 ? this.createInvalidNameError(s, t) : t[s] ? { isValid: !0, sanitized: s } : {
68
69
  isValid: !1,
69
70
  error: `Toolset '${s}' not found. Available toolsets: ${Object.keys(
70
71
  t
@@ -72,19 +73,32 @@ class le {
72
73
  };
73
74
  }
74
75
  /**
75
- * Validates and retrieves modules for a set of toolsets.
76
- * Note: A toolset with only direct tools (no modules) is valid and returns an empty modules array.
76
+ * @param name - The invalid name value
77
+ * @param catalog - The toolset catalog for listing available options
78
+ * @returns Validation result with descriptive error message
79
+ */
80
+ createInvalidNameError(e, t) {
81
+ const s = Object.keys(t).join(", ");
82
+ return !e || typeof e != "string" ? {
83
+ isValid: !1,
84
+ error: `Invalid toolset name provided. Must be a non-empty string. Available toolsets: ${s}`
85
+ } : {
86
+ isValid: !1,
87
+ error: `Empty toolset name provided. Available toolsets: ${s}`
88
+ };
89
+ }
90
+ /**
77
91
  * @param toolsetNames - Array of toolset names to validate
78
92
  * @param catalog - The toolset catalog to validate against
79
93
  * @returns Validation result with modules array if valid
80
94
  */
81
95
  validateToolsetModules(e, t) {
82
96
  try {
83
- for (const r of e)
84
- if (!t[r])
97
+ for (const o of e)
98
+ if (!t[o])
85
99
  return {
86
100
  isValid: !1,
87
- error: `Toolset '${r}' not found in catalog`
101
+ error: `Toolset '${o}' not found in catalog`
88
102
  };
89
103
  return { isValid: !0, modules: this.getModulesForToolSets(e, t) };
90
104
  } catch (s) {
@@ -112,18 +126,31 @@ class le {
112
126
  }
113
127
  }
114
128
  }
115
- const k = ["_meta"];
116
- class ce {
129
+ class j {
117
130
  constructor(e) {
118
131
  d(this, "catalog");
119
132
  d(this, "moduleLoaders");
120
- for (const t of k)
133
+ for (const t of W)
121
134
  if (t in e.catalog)
122
135
  throw new Error(
123
136
  `Toolset key '${t}' is reserved for internal use and cannot be used in the catalog`
124
137
  );
125
138
  this.catalog = e.catalog, this.moduleLoaders = e.moduleLoaders ?? {};
126
139
  }
140
+ static builder() {
141
+ const e = {}, t = {
142
+ catalog(s) {
143
+ return e.catalog = s, t;
144
+ },
145
+ moduleLoaders(s) {
146
+ return e.moduleLoaders = s, t;
147
+ },
148
+ build() {
149
+ return new j(e);
150
+ }
151
+ };
152
+ return t;
153
+ }
127
154
  getAvailableToolsets() {
128
155
  return Object.keys(this.catalog);
129
156
  }
@@ -144,7 +171,7 @@ class ce {
144
171
  error: `Empty toolset name provided. Available toolsets: ${this.getAvailableToolsets().join(
145
172
  ", "
146
173
  )}`
147
- } : k.includes(t) ? {
174
+ } : W.includes(t) ? {
148
175
  isValid: !1,
149
176
  error: `Toolset key '${t}' is reserved for internal use`
150
177
  } : this.catalog[t] ? { isValid: !0, sanitized: t } : {
@@ -156,35 +183,51 @@ class ce {
156
183
  }
157
184
  async resolveToolsForToolsets(e, t) {
158
185
  const s = [];
159
- for (const r of e) {
160
- const i = this.catalog[r];
161
- if (i && (Array.isArray(i.tools) && i.tools.length > 0 && s.push(...i.tools), Array.isArray(i.modules) && i.modules.length > 0))
162
- for (const n of i.modules) {
163
- const l = this.moduleLoaders[n];
164
- if (l)
165
- try {
166
- const c = await l(t);
167
- Array.isArray(c) && c.length > 0 && s.push(...c);
168
- } catch (c) {
169
- console.warn(
170
- `Module loader '${n}' failed for toolset '${r}':`,
171
- c
172
- );
173
- }
174
- }
186
+ for (const o of e) {
187
+ const n = this.catalog[o];
188
+ n && (this.collectDirectTools(n, s), await this.loadModuleTools(n, o, t, s));
175
189
  }
176
190
  return s;
177
191
  }
192
+ /**
193
+ * @param def - The toolset definition
194
+ * @param collected - Mutable array to append direct tools to
195
+ */
196
+ collectDirectTools(e, t) {
197
+ Array.isArray(e.tools) && e.tools.length > 0 && t.push(...e.tools);
198
+ }
199
+ /**
200
+ * @param def - The toolset definition containing module keys
201
+ * @param toolsetName - The toolset name for error messages
202
+ * @param context - Optional context passed to module loaders
203
+ * @param collected - Mutable array to append loaded tools to
204
+ */
205
+ async loadModuleTools(e, t, s, o) {
206
+ if (!(!Array.isArray(e.modules) || e.modules.length === 0))
207
+ for (const n of e.modules) {
208
+ const i = this.moduleLoaders[n];
209
+ if (i)
210
+ try {
211
+ const a = await i(s);
212
+ Array.isArray(a) && a.length > 0 && o.push(...a);
213
+ } catch (a) {
214
+ console.warn(
215
+ `Module loader '${n}' failed for toolset '${t}':`,
216
+ a
217
+ );
218
+ }
219
+ }
220
+ }
178
221
  }
179
- class O extends Error {
180
- constructor(t, s, r, i) {
222
+ class Y extends Error {
223
+ constructor(t, s, o, n) {
181
224
  super(t);
182
225
  d(this, "code");
183
226
  d(this, "details");
184
- this.name = "ToolingError", this.code = s, this.details = r;
227
+ this.name = "ToolingError", this.code = s, this.details = o;
185
228
  }
186
229
  }
187
- class q {
230
+ class C {
188
231
  constructor(e = {}) {
189
232
  d(this, "options");
190
233
  d(this, "names", /* @__PURE__ */ new Set());
@@ -193,6 +236,17 @@ class q {
193
236
  namespaceWithToolset: e.namespaceWithToolset ?? !0
194
237
  };
195
238
  }
239
+ static builder() {
240
+ const e = {}, t = {
241
+ namespaceWithToolset(s) {
242
+ return e.namespaceWithToolset = s, t;
243
+ },
244
+ build() {
245
+ return new C(e);
246
+ }
247
+ };
248
+ return t;
249
+ }
196
250
  getSafeName(e, t) {
197
251
  return !this.options.namespaceWithToolset || t.startsWith(`${e}.`) ? t : `${e}.${t}`;
198
252
  }
@@ -201,7 +255,7 @@ class q {
201
255
  }
202
256
  add(e) {
203
257
  if (this.names.has(e))
204
- throw new O(
258
+ throw new Y(
205
259
  `Tool name collision: '${e}' already registered`,
206
260
  "E_TOOL_NAME_CONFLICT"
207
261
  );
@@ -214,13 +268,13 @@ class q {
214
268
  }
215
269
  mapAndValidate(e, t) {
216
270
  return t.map((s) => {
217
- const r = this.getSafeName(e, s.name);
218
- if (this.has(r))
219
- throw new O(
220
- `Tool name collision for '${r}'`,
271
+ const o = this.getSafeName(e, s.name);
272
+ if (this.has(o))
273
+ throw new Y(
274
+ `Tool name collision for '${o}'`,
221
275
  "E_TOOL_NAME_CONFLICT"
222
276
  );
223
- return { ...s, name: r };
277
+ return { ...s, name: o };
224
278
  });
225
279
  }
226
280
  list() {
@@ -233,7 +287,7 @@ class q {
233
287
  return e;
234
288
  }
235
289
  }
236
- class de {
290
+ class N {
237
291
  constructor(e) {
238
292
  d(this, "server");
239
293
  d(this, "resolver");
@@ -242,13 +296,36 @@ class de {
242
296
  d(this, "exposurePolicy");
243
297
  d(this, "toolRegistry");
244
298
  d(this, "activeToolsets", /* @__PURE__ */ new Set());
245
- this.server = e.server, this.resolver = e.resolver, this.context = e.context, this.onToolsListChanged = e.onToolsListChanged, this.exposurePolicy = e.exposurePolicy, this.toolRegistry = e.toolRegistry ?? new q({ namespaceWithToolset: !0 });
299
+ this.server = e.server, this.resolver = e.resolver, this.context = e.context, this.onToolsListChanged = e.onToolsListChanged, this.exposurePolicy = e.exposurePolicy, this.toolRegistry = e.toolRegistry ?? C.builder().namespaceWithToolset(!0).build();
300
+ }
301
+ static builder() {
302
+ const e = {}, t = {
303
+ server(s) {
304
+ return e.server = s, t;
305
+ },
306
+ resolver(s) {
307
+ return e.resolver = s, t;
308
+ },
309
+ context(s) {
310
+ return e.context = s, t;
311
+ },
312
+ onToolsListChanged(s) {
313
+ return e.onToolsListChanged = s, t;
314
+ },
315
+ exposurePolicy(s) {
316
+ return e.exposurePolicy = s, t;
317
+ },
318
+ toolRegistry(s) {
319
+ return e.toolRegistry = s, t;
320
+ },
321
+ build() {
322
+ return new N(e);
323
+ }
324
+ };
325
+ return t;
246
326
  }
247
327
  /**
248
- * Sends a tool list change notification if configured.
249
- * Logs warnings on failure instead of throwing.
250
328
  * @returns Promise that resolves when notification is sent (or skipped)
251
- * @private
252
329
  */
253
330
  async notifyToolsChanged() {
254
331
  if (this.onToolsListChanged)
@@ -272,59 +349,81 @@ class de {
272
349
  }
273
350
  /**
274
351
  * Enables a single toolset by name.
275
- * Validates the toolset, checks exposure policies, resolves tools, and registers them.
276
352
  * @param toolsetName - The name of the toolset to enable
277
- * @param skipNotification - If true, skips the tool list change notification (for batch operations)
353
+ * @param skipNotification - If true, skips the tool list change notification
278
354
  * @returns Result object with success status and message
279
355
  */
280
356
  async enableToolset(e, t = !1) {
281
- const s = this.resolver.validateToolsetName(e);
282
- if (!s.isValid || !s.sanitized)
283
- return {
284
- success: !1,
285
- message: s.error || "Unknown validation error"
286
- };
287
- const r = s.sanitized;
288
- if (this.activeToolsets.has(r))
289
- return {
290
- success: !1,
291
- message: `Toolset '${r}' is already enabled.`
292
- };
293
- const i = this.checkExposurePolicy(r);
294
- if (!i.allowed)
295
- return { success: !1, message: i.message };
296
- const n = [];
357
+ const s = this.validateToolsetForEnable(e);
358
+ if ("message" in s) return s;
359
+ const { sanitized: o } = s, n = this.checkExposurePolicy(o);
360
+ if (!n.allowed)
361
+ return { success: !1, message: n.message };
362
+ const i = [];
297
363
  try {
298
- const l = await this.resolver.resolveToolsForToolsets(
299
- [r],
300
- this.context
301
- );
302
- if (l && l.length > 0) {
303
- const c = this.toolRegistry.mapAndValidate(
304
- r,
305
- l
306
- );
307
- for (const a of c)
308
- this.registerSingleTool(a, r), n.push(a.name);
309
- }
310
- return this.activeToolsets.add(r), t || await this.notifyToolsChanged(), {
311
- success: !0,
312
- message: `Toolset '${r}' enabled successfully. Registered ${l?.length ?? 0} tools.`
313
- };
314
- } catch (l) {
315
- return n.length > 0 && console.warn(
316
- `Partial failure enabling toolset '${r}'. ${n.length} tools were registered but toolset activation failed. Tools remain registered due to MCP limitations: ${n.join(", ")}`
317
- ), {
364
+ const a = await this.resolveAndRegisterTools(o, i);
365
+ return this.activeToolsets.add(o), t || await this.notifyToolsChanged(), this.buildEnableResult(o, a);
366
+ } catch (a) {
367
+ return this.handlePartialFailure(o, i), {
318
368
  success: !1,
319
- message: `Failed to enable toolset '${r}': ${l instanceof Error ? l.message : "Unknown error"}`
369
+ message: `Failed to enable toolset '${o}': ${a instanceof Error ? a.message : "Unknown error"}`
320
370
  };
321
371
  }
322
372
  }
323
373
  /**
324
- * Checks if a toolset is allowed by the exposure policy.
374
+ * @param toolsetName - The raw toolset name to validate
375
+ * @returns Error result if invalid, or `{ sanitized }` to continue
376
+ */
377
+ validateToolsetForEnable(e) {
378
+ const t = this.resolver.validateToolsetName(e);
379
+ return !t.isValid || !t.sanitized ? {
380
+ success: !1,
381
+ message: t.error || "Unknown validation error"
382
+ } : this.activeToolsets.has(t.sanitized) ? {
383
+ success: !1,
384
+ message: `Toolset '${t.sanitized}' is already enabled.`
385
+ } : { sanitized: t.sanitized };
386
+ }
387
+ /**
388
+ * @param sanitized - The validated toolset name
389
+ * @param registeredTools - Mutable array tracking registered tool names for rollback
390
+ * @returns The number of tools resolved
391
+ */
392
+ async resolveAndRegisterTools(e, t) {
393
+ const s = await this.resolver.resolveToolsForToolsets(
394
+ [e],
395
+ this.context
396
+ );
397
+ if (s && s.length > 0) {
398
+ const o = this.toolRegistry.mapAndValidate(e, s);
399
+ for (const n of o)
400
+ this.registerSingleTool(n, e), t.push(n.name);
401
+ }
402
+ return s?.length ?? 0;
403
+ }
404
+ /**
405
+ * @param sanitized - The toolset name
406
+ * @param toolCount - Number of tools registered
407
+ * @returns Success result object
408
+ */
409
+ buildEnableResult(e, t) {
410
+ return {
411
+ success: !0,
412
+ message: `Toolset '${e}' enabled successfully. Registered ${t} tools.`
413
+ };
414
+ }
415
+ /**
416
+ * @param sanitized - The toolset name that partially failed
417
+ * @param registeredTools - Tools that were registered before the failure
418
+ */
419
+ handlePartialFailure(e, t) {
420
+ t.length > 0 && console.warn(
421
+ `Partial failure enabling toolset '${e}'. ${t.length} tools were registered but toolset activation failed. Tools remain registered due to MCP limitations: ${t.join(", ")}`
422
+ );
423
+ }
424
+ /**
325
425
  * @param toolsetName - The sanitized toolset name to check
326
426
  * @returns Object indicating if allowed and reason message if not
327
- * @private
328
427
  */
329
428
  checkExposurePolicy(e) {
330
429
  return this.exposurePolicy?.allowlist && !this.exposurePolicy.allowlist.includes(e) ? {
@@ -342,10 +441,8 @@ class de {
342
441
  }) : { allowed: !0, message: "" };
343
442
  }
344
443
  /**
345
- * Registers a single tool with the MCP server.
346
444
  * @param tool - The tool definition to register
347
445
  * @param toolsetKey - The toolset key for tracking
348
- * @private
349
446
  */
350
447
  registerSingleTool(e, t) {
351
448
  e.annotations && Object.keys(e.annotations).length > 0 && e.annotations ? this.server.tool(
@@ -353,27 +450,25 @@ class de {
353
450
  e.description,
354
451
  e.inputSchema,
355
452
  e.annotations,
356
- async (r) => await e.handler(r)
453
+ async (o) => await e.handler(o)
357
454
  ) : this.server.tool(
358
455
  e.name,
359
456
  e.description,
360
457
  e.inputSchema,
361
- async (r) => await e.handler(r)
458
+ async (o) => await e.handler(o)
362
459
  ), this.toolRegistry.addForToolset(t, e.name);
363
460
  }
364
461
  /**
365
- * Disables a toolset by name.
366
- * Note: Due to MCP limitations, tools remain registered but the toolset is marked inactive.
367
462
  * @param toolsetName - The name of the toolset to disable
368
463
  * @returns Result object with success status and message
369
464
  */
370
465
  async disableToolset(e) {
371
466
  const t = this.resolver.validateToolsetName(e);
372
467
  if (!t.isValid || !t.sanitized) {
373
- const r = Array.from(this.activeToolsets).join(", ") || "none";
468
+ const o = Array.from(this.activeToolsets).join(", ") || "none";
374
469
  return {
375
470
  success: !1,
376
- message: `${t.error || "Unknown validation error"} Active toolsets: ${r}`
471
+ message: `${t.error || "Unknown validation error"} Active toolsets: ${o}`
377
472
  };
378
473
  }
379
474
  const s = t.sanitized;
@@ -397,30 +492,27 @@ class de {
397
492
  };
398
493
  }
399
494
  /**
400
- * Enables multiple toolsets in a batch operation.
401
- * Sends a single notification after all toolsets are processed.
402
495
  * @param toolsetNames - Array of toolset names to enable
403
496
  * @returns Result object with overall success status and individual results
404
497
  */
405
498
  async enableToolsets(e) {
406
499
  const t = [];
407
- for (const n of e)
500
+ for (const i of e)
408
501
  try {
409
- const l = await this.enableToolset(n, !0);
410
- t.push({ name: n, ...l });
411
- } catch (l) {
502
+ const a = await this.enableToolset(i, !0);
503
+ t.push({ name: i, ...a });
504
+ } catch (a) {
412
505
  t.push({
413
- name: n,
506
+ name: i,
414
507
  success: !1,
415
- message: l instanceof Error ? l.message : "Unknown error",
508
+ message: a instanceof Error ? a.message : "Unknown error",
416
509
  code: "E_INTERNAL"
417
510
  });
418
511
  }
419
- const s = t.every((n) => n.success), r = t.some((n) => n.success), i = s ? "All toolsets enabled" : r ? "Some toolsets failed to enable" : "All toolsets failed to enable";
420
- return r && await this.notifyToolsChanged(), { success: s, results: t, message: i };
512
+ const s = t.every((i) => i.success), o = t.some((i) => i.success), n = s ? "All toolsets enabled" : o ? "Some toolsets failed to enable" : "All toolsets failed to enable";
513
+ return o && await this.notifyToolsChanged(), { success: s, results: t, message: n };
421
514
  }
422
515
  /**
423
- * Enables all available toolsets in a batch operation.
424
516
  * @returns Result object with overall success status and individual results
425
517
  */
426
518
  async enableAllToolsets() {
@@ -428,104 +520,104 @@ class de {
428
520
  return this.enableToolsets(e);
429
521
  }
430
522
  }
431
- const b = "_meta";
432
- function ue(o, e, t, s) {
433
- (s?.mode ?? "DYNAMIC") === "DYNAMIC" && (t.addForToolset(b, "enable_toolset"), o.tool(
523
+ const w = "_meta";
524
+ function xe(r, e, t, s) {
525
+ (s?.mode ?? "DYNAMIC") === "DYNAMIC" && (t.addForToolset(w, "enable_toolset"), r.tool(
434
526
  "enable_toolset",
435
527
  "Enable a toolset by name",
436
- { name: v.string().describe("Toolset name") },
528
+ { name: g.string().describe("Toolset name") },
437
529
  { destructiveHint: !0, idempotentHint: !0 },
438
- async (i) => {
439
- const n = await e.enableToolset(i.name);
530
+ async (n) => {
531
+ const i = await e.enableToolset(n.name);
440
532
  return {
441
- content: [{ type: "text", text: JSON.stringify(n) }]
533
+ content: [{ type: "text", text: JSON.stringify(i) }]
442
534
  };
443
535
  }
444
- ), t.addForToolset(b, "disable_toolset"), o.tool(
536
+ ), t.addForToolset(w, "disable_toolset"), r.tool(
445
537
  "disable_toolset",
446
538
  "Disable a toolset by name (state only)",
447
- { name: v.string().describe("Toolset name") },
539
+ { name: g.string().describe("Toolset name") },
448
540
  { destructiveHint: !0, idempotentHint: !0 },
449
- async (i) => {
450
- const n = await e.disableToolset(i.name);
541
+ async (n) => {
542
+ const i = await e.disableToolset(n.name);
451
543
  return {
452
- content: [{ type: "text", text: JSON.stringify(n) }]
544
+ content: [{ type: "text", text: JSON.stringify(i) }]
453
545
  };
454
546
  }
455
- ), t.addForToolset(b, "list_toolsets"), o.tool(
547
+ ), t.addForToolset(w, "list_toolsets"), r.tool(
456
548
  "list_toolsets",
457
549
  "List available toolsets with active status and definitions",
458
550
  {},
459
551
  { readOnlyHint: !0, idempotentHint: !0 },
460
552
  async () => {
461
- const i = e.getAvailableToolsets(), n = e.getStatus().toolsetToTools, l = i.map((c) => {
462
- const a = e.getToolsetDefinition(c);
553
+ const n = e.getAvailableToolsets(), i = e.getStatus().toolsetToTools, a = n.map((l) => {
554
+ const c = e.getToolsetDefinition(l);
463
555
  return {
464
- key: c,
465
- active: e.isActive(c),
466
- definition: a ? {
467
- name: a.name,
468
- description: a.description,
469
- modules: a.modules ?? [],
470
- decisionCriteria: a.decisionCriteria ?? void 0
556
+ key: l,
557
+ active: e.isActive(l),
558
+ definition: c ? {
559
+ name: c.name,
560
+ description: c.description,
561
+ modules: c.modules ?? [],
562
+ decisionCriteria: c.decisionCriteria ?? void 0
471
563
  } : null,
472
- tools: n[c] ?? []
564
+ tools: i[l] ?? []
473
565
  };
474
566
  });
475
567
  return {
476
568
  content: [
477
- { type: "text", text: JSON.stringify({ toolsets: l }) }
569
+ { type: "text", text: JSON.stringify({ toolsets: a }) }
478
570
  ]
479
571
  };
480
572
  }
481
- ), t.addForToolset(b, "describe_toolset"), o.tool(
573
+ ), t.addForToolset(w, "describe_toolset"), r.tool(
482
574
  "describe_toolset",
483
575
  "Describe a toolset with definition, active status and tools",
484
- { name: v.string().describe("Toolset name") },
576
+ { name: g.string().describe("Toolset name") },
485
577
  { readOnlyHint: !0, idempotentHint: !0 },
486
- async (i) => {
487
- const n = e.getToolsetDefinition(i.name), l = e.getStatus().toolsetToTools;
488
- if (!n)
578
+ async (n) => {
579
+ const i = e.getToolsetDefinition(n.name), a = e.getStatus().toolsetToTools;
580
+ if (!i)
489
581
  return {
490
582
  content: [
491
583
  {
492
584
  type: "text",
493
- text: JSON.stringify({ error: `Unknown toolset '${i.name}'` })
585
+ text: JSON.stringify({ error: `Unknown toolset '${n.name}'` })
494
586
  }
495
587
  ]
496
588
  };
497
- const c = {
498
- key: i.name,
499
- active: e.isActive(i.name),
589
+ const l = {
590
+ key: n.name,
591
+ active: e.isActive(n.name),
500
592
  definition: {
501
- name: n.name,
502
- description: n.description,
503
- modules: n.modules ?? [],
504
- decisionCriteria: n.decisionCriteria ?? void 0
593
+ name: i.name,
594
+ description: i.description,
595
+ modules: i.modules ?? [],
596
+ decisionCriteria: i.decisionCriteria ?? void 0
505
597
  },
506
- tools: l[i.name] ?? []
598
+ tools: a[n.name] ?? []
507
599
  };
508
600
  return {
509
- content: [{ type: "text", text: JSON.stringify(c) }]
601
+ content: [{ type: "text", text: JSON.stringify(l) }]
510
602
  };
511
603
  }
512
- )), t.addForToolset(b, "list_tools"), o.tool(
604
+ )), t.addForToolset(w, "list_tools"), r.tool(
513
605
  "list_tools",
514
606
  "List currently registered tool names (best effort)",
515
607
  {},
516
608
  { readOnlyHint: !0, idempotentHint: !0 },
517
609
  async () => {
518
- const i = e.getStatus(), n = {
519
- tools: i.tools,
520
- toolsetToTools: i.toolsetToTools
610
+ const n = e.getStatus(), i = {
611
+ tools: n.tools,
612
+ toolsetToTools: n.toolsetToTools
521
613
  };
522
614
  return {
523
- content: [{ type: "text", text: JSON.stringify(n) }]
615
+ content: [{ type: "text", text: JSON.stringify(i) }]
524
616
  };
525
617
  }
526
618
  );
527
619
  }
528
- class C {
620
+ class A {
529
621
  constructor(e) {
530
622
  d(this, "mode");
531
623
  d(this, "resolver");
@@ -533,32 +625,51 @@ class C {
533
625
  d(this, "toolsetValidator");
534
626
  d(this, "initPromise");
535
627
  d(this, "initError", null);
536
- this.toolsetValidator = new le();
628
+ this.toolsetValidator = L.builder().build();
537
629
  const t = e.startup ?? {}, s = this.resolveStartupConfig(t, e.catalog);
538
- this.mode = s.mode, this.resolver = new ce({
539
- catalog: e.catalog,
540
- moduleLoaders: e.moduleLoaders
541
- });
542
- const r = new q({
543
- namespaceWithToolset: e.exposurePolicy?.namespaceToolsWithSetKey ?? !0
544
- });
545
- this.manager = new de({
546
- server: e.server,
547
- resolver: this.resolver,
548
- context: e.context,
549
- onToolsListChanged: e.notifyToolsListChanged,
550
- exposurePolicy: e.exposurePolicy,
551
- toolRegistry: r
552
- }), e.registerMetaTools !== !1 && ue(e.server, this.manager, r, { mode: this.mode });
630
+ this.mode = s.mode, this.resolver = j.builder().catalog(e.catalog).moduleLoaders(e.moduleLoaders ?? {}).build();
631
+ const o = C.builder().namespaceWithToolset(
632
+ e.exposurePolicy?.namespaceToolsWithSetKey ?? !0
633
+ ).build(), n = N.builder().server(e.server).resolver(this.resolver).context(e.context).toolRegistry(o);
634
+ e.notifyToolsListChanged && n.onToolsListChanged(e.notifyToolsListChanged), e.exposurePolicy && n.exposurePolicy(e.exposurePolicy), this.manager = n.build(), e.registerMetaTools !== !1 && xe(e.server, this.manager, o, { mode: this.mode });
553
635
  const i = s.toolsets;
554
636
  this.initPromise = this.initializeToolsets(i);
555
637
  }
638
+ static builder() {
639
+ const e = {}, t = {
640
+ server(s) {
641
+ return e.server = s, t;
642
+ },
643
+ catalog(s) {
644
+ return e.catalog = s, t;
645
+ },
646
+ moduleLoaders(s) {
647
+ return e.moduleLoaders = s, t;
648
+ },
649
+ exposurePolicy(s) {
650
+ return e.exposurePolicy = s, t;
651
+ },
652
+ context(s) {
653
+ return e.context = s, t;
654
+ },
655
+ notifyToolsListChanged(s) {
656
+ return e.notifyToolsListChanged = s, t;
657
+ },
658
+ startup(s) {
659
+ return e.startup = s, t;
660
+ },
661
+ registerMetaTools(s) {
662
+ return e.registerMetaTools = s, t;
663
+ },
664
+ build() {
665
+ return new A(e);
666
+ }
667
+ };
668
+ return t;
669
+ }
556
670
  /**
557
- * Initializes toolsets asynchronously during construction.
558
- * Stores any errors for later retrieval via ensureReady().
559
671
  * @param initial - The toolsets to initialize or "ALL"
560
672
  * @returns Promise that resolves when initialization is complete
561
- * @private
562
673
  */
563
674
  async initializeToolsets(e) {
564
675
  try {
@@ -567,50 +678,46 @@ class C {
567
678
  this.initError = t instanceof Error ? t : new Error(String(t)), console.error("Failed to initialize toolsets:", this.initError);
568
679
  }
569
680
  }
570
- /**
571
- * Waits for the orchestrator to be fully initialized.
572
- * Call this before using the orchestrator to ensure all toolsets are loaded.
573
- * @throws {Error} If initialization failed
574
- */
575
681
  async ensureReady() {
576
682
  if (await this.initPromise, this.initError)
577
683
  throw this.initError;
578
684
  }
579
- /**
580
- * Checks if the orchestrator has finished initialization.
581
- * Does not throw on error - use ensureReady() for that.
582
- * @returns Promise that resolves to true if ready, false if initialization failed
583
- */
584
685
  async isReady() {
585
686
  return await this.initPromise, this.initError === null;
586
687
  }
587
688
  resolveStartupConfig(e, t) {
588
- if (e.mode) {
589
- if (e.mode === "DYNAMIC" && e.toolsets)
590
- return console.warn("startup.toolsets provided but ignored in DYNAMIC mode"), { mode: "DYNAMIC" };
591
- if (e.mode === "STATIC") {
592
- if (e.toolsets === "ALL")
593
- return { mode: "STATIC", toolsets: "ALL" };
594
- const s = Array.isArray(e.toolsets) ? e.toolsets : [], r = [];
595
- for (const i of s) {
596
- const { isValid: n, sanitized: l, error: c } = this.toolsetValidator.validateToolsetName(i, t);
597
- n && l ? r.push(l) : c && console.warn(c);
598
- }
599
- if (s.length > 0 && r.length === 0)
600
- throw new Error(
601
- "STATIC mode requires valid toolsets or 'ALL'; none were valid"
602
- );
603
- return { mode: "STATIC", toolsets: r };
604
- }
605
- return { mode: e.mode };
689
+ return e.mode ? this.resolveExplicitMode(e.mode, e.toolsets, t) : this.inferModeFromToolsets(e, t);
690
+ }
691
+ /**
692
+ * @param mode - The explicit mode
693
+ * @param toolsets - Optional toolsets from startup config
694
+ * @param catalog - The toolset catalog to validate against
695
+ * @returns Resolved mode and toolsets
696
+ */
697
+ resolveExplicitMode(e, t, s) {
698
+ if (e === "DYNAMIC" && t)
699
+ return console.warn("startup.toolsets provided but ignored in DYNAMIC mode"), { mode: "DYNAMIC" };
700
+ if (e === "STATIC") {
701
+ if (t === "ALL")
702
+ return { mode: "STATIC", toolsets: "ALL" };
703
+ const o = Array.isArray(t) ? t : [], n = this.validateAndCollectToolsets(o, s);
704
+ if (o.length > 0 && n.length === 0)
705
+ throw new Error(
706
+ "STATIC mode requires valid toolsets or 'ALL'; none were valid"
707
+ );
708
+ return { mode: "STATIC", toolsets: n };
606
709
  }
710
+ return { mode: e };
711
+ }
712
+ /**
713
+ * @param startup - Startup config without an explicit mode
714
+ * @param catalog - The toolset catalog to validate against
715
+ * @returns Inferred mode and toolsets
716
+ */
717
+ inferModeFromToolsets(e, t) {
607
718
  if (e.toolsets === "ALL") return { mode: "STATIC", toolsets: "ALL" };
608
719
  if (Array.isArray(e.toolsets) && e.toolsets.length > 0) {
609
- const s = [];
610
- for (const r of e.toolsets) {
611
- const { isValid: i, sanitized: n, error: l } = this.toolsetValidator.validateToolsetName(r, t);
612
- i && n ? s.push(n) : l && console.warn(l);
613
- }
720
+ const s = this.validateAndCollectToolsets(e.toolsets, t);
614
721
  if (s.length === 0)
615
722
  throw new Error(
616
723
  "STATIC mode requires valid toolsets or 'ALL'; none were valid"
@@ -619,6 +726,19 @@ class C {
619
726
  }
620
727
  return { mode: "DYNAMIC" };
621
728
  }
729
+ /**
730
+ * @param names - Array of toolset names to validate
731
+ * @param catalog - The toolset catalog to validate against
732
+ * @returns Array of valid, sanitized toolset names
733
+ */
734
+ validateAndCollectToolsets(e, t) {
735
+ const s = [];
736
+ for (const o of e) {
737
+ const { isValid: n, sanitized: i, error: a } = this.toolsetValidator.validateToolsetName(o, t);
738
+ n && i ? s.push(i) : a && console.warn(a);
739
+ }
740
+ return s;
741
+ }
622
742
  getMode() {
623
743
  return this.mode;
624
744
  }
@@ -626,10 +746,10 @@ class C {
626
746
  return this.manager;
627
747
  }
628
748
  }
629
- var x, P;
630
- class F {
749
+ var T, M;
750
+ const D = class D {
631
751
  constructor(e = {}) {
632
- A(this, x);
752
+ x(this, T);
633
753
  d(this, "storage", /* @__PURE__ */ new Map());
634
754
  d(this, "maxSize");
635
755
  d(this, "ttlMs");
@@ -640,6 +760,26 @@ class F {
640
760
  const t = e.pruneIntervalMs ?? 1e3 * 60 * 10;
641
761
  this.pruneInterval = setInterval(() => this.pruneExpired(), t);
642
762
  }
763
+ static builder() {
764
+ const e = {}, t = {
765
+ maxSize(s) {
766
+ return e.maxSize = s, t;
767
+ },
768
+ ttlMs(s) {
769
+ return e.ttlMs = s, t;
770
+ },
771
+ pruneIntervalMs(s) {
772
+ return e.pruneIntervalMs = s, t;
773
+ },
774
+ onEvict(s) {
775
+ return e.onEvict = s, t;
776
+ },
777
+ build() {
778
+ return new D(e);
779
+ }
780
+ };
781
+ return t;
782
+ }
643
783
  getEntryCount() {
644
784
  return this.storage.size;
645
785
  }
@@ -659,122 +799,112 @@ class F {
659
799
  this.storage.set(e, s);
660
800
  }
661
801
  /**
662
- * Removes an entry from the cache.
663
- * Calls the onEvict callback if configured.
664
802
  * @param key - The key to remove
665
803
  */
666
804
  delete(e) {
667
805
  const t = this.storage.get(e);
668
- t && (this.storage.delete(e), m(this, x, P).call(this, e, t.resource));
806
+ t && (this.storage.delete(e), m(this, T, M).call(this, e, t.resource));
669
807
  }
670
808
  /**
671
- * Stops the background pruning interval and optionally clears all entries.
672
809
  * @param clearEntries - If true, also removes all entries and calls onEvict for each
673
810
  */
674
811
  stop(e = !1) {
675
812
  this.pruneInterval && (clearInterval(this.pruneInterval), this.pruneInterval = void 0), e && this.clear();
676
813
  }
677
- /**
678
- * Clears all entries from the cache.
679
- * Calls onEvict for each entry being removed.
680
- */
681
814
  clear() {
682
815
  const e = Array.from(this.storage.entries());
683
816
  this.storage.clear();
684
817
  for (const [t, s] of e)
685
- m(this, x, P).call(this, t, s.resource);
818
+ m(this, T, M).call(this, t, s.resource);
686
819
  }
687
- /**
688
- * Evicts the least recently used entry from the cache.
689
- * @private
690
- */
691
820
  evictLeastRecentlyUsed() {
692
821
  const e = this.storage.keys().next().value;
693
822
  e && this.delete(e);
694
823
  }
695
- /**
696
- * Removes all expired entries from the cache.
697
- * @private
698
- */
699
824
  pruneExpired() {
700
825
  const e = Date.now(), t = [];
701
- for (const [s, r] of this.storage.entries())
702
- e - r.lastAccessed > this.ttlMs && t.push(s);
826
+ for (const [s, o] of this.storage.entries())
827
+ e - o.lastAccessed > this.ttlMs && t.push(s);
703
828
  for (const s of t)
704
829
  this.delete(s);
705
830
  }
706
- }
707
- x = new WeakSet(), /**
708
- * Safely calls the evict callback, catching and logging any errors.
831
+ };
832
+ T = new WeakSet(), /**
709
833
  * @param key - The key being evicted
710
834
  * @param resource - The resource being evicted
711
- * @private
712
835
  */
713
- P = function(e, t) {
836
+ M = function(e, t) {
714
837
  if (this.onEvict)
715
838
  try {
716
839
  const s = this.onEvict(e, t);
717
- s instanceof Promise && s.catch((r) => {
718
- console.warn(`Error in cache eviction callback for key '${e}':`, r);
840
+ s instanceof Promise && s.catch((o) => {
841
+ console.warn(`Error in cache eviction callback for key '${e}':`, o);
719
842
  });
720
843
  } catch (s) {
721
844
  console.warn(`Error in cache eviction callback for key '${e}':`, s);
722
845
  }
723
846
  };
724
- function V(o, e, t, s) {
725
- const r = ["/mcp", "/healthz", "/tools", "/.well-known/mcp-config"];
726
- for (const i of t) {
727
- const n = `${e}${i.path}`;
728
- if (r.some(
729
- (a) => n.startsWith(`${e}${a}`)
847
+ let E = D;
848
+ function rt(r) {
849
+ return r;
850
+ }
851
+ function ot(r) {
852
+ return r;
853
+ }
854
+ function Z(r, e, t, s) {
855
+ const o = ["/mcp", "/healthz", "/tools", "/.well-known/mcp-config"];
856
+ for (const n of t) {
857
+ const i = `${e}${n.path}`;
858
+ if (o.some(
859
+ (c) => i.startsWith(`${e}${c}`)
730
860
  )) {
731
861
  console.warn(
732
- `Custom endpoint ${i.method} ${i.path} conflicts with built-in MCP endpoint. Skipping registration.`
862
+ `Custom endpoint ${n.method} ${n.path} conflicts with built-in MCP endpoint. Skipping registration.`
733
863
  );
734
864
  continue;
735
865
  }
736
- const c = i.method.toLowerCase();
737
- o[c](n, async (a, u) => {
866
+ const l = n.method.toLowerCase();
867
+ r[l](i, async (c, u) => {
738
868
  try {
739
- const h = a.headers["mcp-client-id"]?.trim(), g = h && h.length > 0 ? h : `anon-${S()}`;
740
- let w;
741
- if (i.bodySchema) {
742
- const y = i.bodySchema.safeParse(a.body);
743
- if (!y.success)
744
- return E(u, "body", y.error);
745
- w = y.data;
869
+ const f = c.headers["mcp-client-id"]?.trim(), v = f && f.length > 0 ? f : `anon-${S()}`;
870
+ let b;
871
+ if (n.bodySchema) {
872
+ const p = n.bodySchema.safeParse(c.body);
873
+ if (!p.success)
874
+ return P(u, "body", p.error);
875
+ b = p.data;
746
876
  }
747
- let T = {};
748
- if (i.querySchema) {
749
- const y = i.querySchema.safeParse(a.query);
750
- if (!y.success)
751
- return E(u, "query", y.error);
752
- T = y.data;
877
+ let F = {};
878
+ if (n.querySchema) {
879
+ const p = n.querySchema.safeParse(c.query);
880
+ if (!p.success)
881
+ return P(u, "query", p.error);
882
+ F = p.data;
753
883
  }
754
- let I = {};
755
- if (i.paramsSchema) {
756
- const y = i.paramsSchema.safeParse(a.params);
757
- if (!y.success)
758
- return E(u, "params", y.error);
759
- I = y.data;
884
+ let _ = {};
885
+ if (n.paramsSchema) {
886
+ const p = n.paramsSchema.safeParse(c.params);
887
+ if (!p.success)
888
+ return P(u, "params", p.error);
889
+ _ = p.data;
760
890
  }
761
- const $ = {
762
- body: w,
763
- query: T,
764
- params: I,
765
- headers: a.headers,
766
- clientId: g
891
+ const K = {
892
+ body: b,
893
+ query: F,
894
+ params: _,
895
+ headers: c.headers,
896
+ clientId: v
767
897
  };
768
898
  if (s?.contextExtractor) {
769
- const y = await s.contextExtractor(a);
770
- Object.assign($, y);
899
+ const p = await s.contextExtractor(c);
900
+ Object.assign(K, p);
771
901
  }
772
- const L = await i.handler($);
773
- if (i.responseSchema) {
774
- const y = i.responseSchema.safeParse(L);
775
- return y.success ? y.data : (console.error(
776
- `Response validation failed for ${i.method} ${i.path}:`,
777
- y.error
902
+ const B = await n.handler(K);
903
+ if (n.responseSchema) {
904
+ const p = n.responseSchema.safeParse(B);
905
+ return p.success ? p.data : (console.error(
906
+ `Response validation failed for ${n.method} ${n.path}:`,
907
+ p.error
778
908
  ), u.code(500), {
779
909
  error: {
780
910
  code: "RESPONSE_VALIDATION_ERROR",
@@ -782,23 +912,23 @@ function V(o, e, t, s) {
782
912
  }
783
913
  });
784
914
  }
785
- return L;
786
- } catch (h) {
915
+ return B;
916
+ } catch (f) {
787
917
  return console.error(
788
- `Error in custom endpoint ${i.method} ${i.path}:`,
789
- h
918
+ `Error in custom endpoint ${n.method} ${n.path}:`,
919
+ f
790
920
  ), u.code(500), {
791
921
  error: {
792
922
  code: "INTERNAL_ERROR",
793
- message: h instanceof Error ? h.message : "Internal server error"
923
+ message: f instanceof Error ? f.message : "Internal server error"
794
924
  }
795
925
  };
796
926
  }
797
927
  });
798
928
  }
799
929
  }
800
- function E(o, e, t) {
801
- return o.code(400), {
930
+ function P(r, e, t) {
931
+ return r.code(400), {
802
932
  error: {
803
933
  code: "VALIDATION_ERROR",
804
934
  message: `Validation failed for ${e}`,
@@ -806,8 +936,9 @@ function E(o, e, t) {
806
936
  }
807
937
  };
808
938
  }
809
- class he {
810
- constructor(e, t, s = {}, r, i, n) {
939
+ const Se = g.string({ message: "Missing required mcp-client-id header" }).trim().min(1, "mcp-client-id header must not be empty");
940
+ class O {
941
+ constructor(e, t, s = {}, o, n, i) {
811
942
  d(this, "options");
812
943
  d(this, "defaultManager");
813
944
  d(this, "createBundle");
@@ -816,12 +947,12 @@ class he {
816
947
  d(this, "app", null);
817
948
  d(this, "configSchema");
818
949
  // Per-client server bundles and per-client session transports
819
- d(this, "clientCache", new F({
950
+ d(this, "clientCache", new E({
820
951
  onEvict: (e, t) => {
821
952
  this.cleanupBundle(t);
822
953
  }
823
954
  }));
824
- this.defaultManager = e, this.createBundle = t, this.sessionContextResolver = i, this.baseContext = n, this.options = {
955
+ this.defaultManager = e, this.createBundle = t, this.sessionContextResolver = n, this.baseContext = i, this.options = {
825
956
  host: s.host ?? "0.0.0.0",
826
957
  port: s.port ?? 3e3,
827
958
  basePath: s.basePath ?? "/",
@@ -829,14 +960,89 @@ class he {
829
960
  logger: s.logger ?? !1,
830
961
  app: s.app,
831
962
  customEndpoints: s.customEndpoints
832
- }, this.configSchema = r;
963
+ }, this.configSchema = o;
964
+ }
965
+ static builder() {
966
+ let e, t;
967
+ const s = {};
968
+ let o, n, i;
969
+ const a = {
970
+ defaultManager(l) {
971
+ return e = l, a;
972
+ },
973
+ createBundle(l) {
974
+ return t = l, a;
975
+ },
976
+ host(l) {
977
+ return s.host = l, a;
978
+ },
979
+ port(l) {
980
+ return s.port = l, a;
981
+ },
982
+ basePath(l) {
983
+ return s.basePath = l, a;
984
+ },
985
+ cors(l) {
986
+ return s.cors = l, a;
987
+ },
988
+ logger(l) {
989
+ return s.logger = l, a;
990
+ },
991
+ app(l) {
992
+ return s.app = l, a;
993
+ },
994
+ customEndpoints(l) {
995
+ return s.customEndpoints = l, a;
996
+ },
997
+ configSchema(l) {
998
+ return o = l, a;
999
+ },
1000
+ sessionContextResolver(l) {
1001
+ return n = l, a;
1002
+ },
1003
+ baseContext(l) {
1004
+ return i = l, a;
1005
+ },
1006
+ build() {
1007
+ return new O(e, t, s, o, n, i);
1008
+ }
1009
+ };
1010
+ return a;
833
1011
  }
834
1012
  async start() {
835
1013
  if (this.app) return;
836
- const e = this.options.app ?? N({ logger: this.options.logger });
837
- this.options.cors && await e.register(D, { origin: !0 });
838
- const t = this.options.basePath.endsWith("/") ? this.options.basePath.slice(0, -1) : this.options.basePath;
839
- e.get(`${t}/healthz`, async () => ({ ok: !0 })), e.get(`${t}/tools`, async () => this.defaultManager.getStatus()), e.get(`${t}/.well-known/mcp-config`, async (s, r) => (r.header("Content-Type", "application/schema+json; charset=utf-8"), this.configSchema ?? {
1014
+ const e = this.options.app ?? U({ logger: this.options.logger });
1015
+ this.options.cors && await e.register(J, { origin: !0 });
1016
+ const t = this.normalizeBasePath(this.options.basePath);
1017
+ this.registerHealthEndpoint(e, t), this.registerToolsEndpoint(e, t), this.registerConfigDiscoveryEndpoint(e, t), this.registerMcpPostEndpoint(e, t), this.registerMcpGetEndpoint(e, t), this.registerMcpDeleteEndpoint(e, t), this.options.customEndpoints && this.options.customEndpoints.length > 0 && Z(e, t, this.options.customEndpoints), this.options.app || await e.listen({ host: this.options.host, port: this.options.port }), this.app = e;
1018
+ }
1019
+ /**
1020
+ * @param basePath - The base path to normalize
1021
+ * @returns Normalized base path without trailing slash
1022
+ */
1023
+ normalizeBasePath(e) {
1024
+ return e.endsWith("/") ? e.slice(0, -1) : e;
1025
+ }
1026
+ /**
1027
+ * @param app - Fastify instance
1028
+ * @param base - Base path for routes
1029
+ */
1030
+ registerHealthEndpoint(e, t) {
1031
+ e.get(`${t}/healthz`, async () => ({ ok: !0 }));
1032
+ }
1033
+ /**
1034
+ * @param app - Fastify instance
1035
+ * @param base - Base path for routes
1036
+ */
1037
+ registerToolsEndpoint(e, t) {
1038
+ e.get(`${t}/tools`, async () => this.defaultManager.getStatus());
1039
+ }
1040
+ /**
1041
+ * @param app - Fastify instance
1042
+ * @param base - Base path for routes
1043
+ */
1044
+ registerConfigDiscoveryEndpoint(e, t) {
1045
+ e.get(`${t}/.well-known/mcp-config`, async (s, o) => (o.header("Content-Type", "application/schema+json; charset=utf-8"), this.configSchema ?? {
840
1046
  $schema: "https://json-schema.org/draft/2020-12/schema",
841
1047
  title: "MCP Session Configuration",
842
1048
  description: "Schema for the /mcp endpoint configuration",
@@ -845,76 +1051,102 @@ class he {
845
1051
  required: [],
846
1052
  "x-mcp-version": "1.0",
847
1053
  "x-query-style": "dot+bracket"
848
- })), e.post(
1054
+ }));
1055
+ }
1056
+ /**
1057
+ * @param app - Fastify instance
1058
+ * @param base - Base path for routes
1059
+ */
1060
+ registerMcpPostEndpoint(e, t) {
1061
+ e.post(
849
1062
  `${t}/mcp`,
850
- async (s, r) => {
851
- const i = s.headers["mcp-client-id"]?.trim(), n = i && i.length > 0 ? i : `anon-${S()}`, l = !n.startsWith("anon-"), { cacheKey: c, mergedContext: a } = this.resolveSessionContext(
1063
+ async (s, o) => {
1064
+ const n = Se.safeParse(
1065
+ s.headers["mcp-client-id"]
1066
+ );
1067
+ if (!n.success)
1068
+ return o.code(400), {
1069
+ jsonrpc: "2.0",
1070
+ error: { code: -32600, message: n.error.issues[0].message },
1071
+ id: null
1072
+ };
1073
+ const i = n.data, { cacheKey: a, mergedContext: l } = this.resolveSessionContext(
852
1074
  s,
853
- n
1075
+ i
854
1076
  );
855
- let u = l ? this.clientCache.get(c) : null;
856
- if (!u) {
857
- const w = this.createBundle(a);
858
- u = {
859
- server: w.server,
860
- orchestrator: w.orchestrator,
1077
+ let c = this.clientCache.get(a);
1078
+ if (!c) {
1079
+ const v = this.createBundle(l);
1080
+ c = {
1081
+ server: v.server,
1082
+ orchestrator: v.orchestrator,
861
1083
  sessions: /* @__PURE__ */ new Map()
862
- }, l && this.clientCache.set(c, u);
1084
+ }, this.clientCache.set(a, c);
863
1085
  }
864
- const h = s.headers["mcp-session-id"];
865
- let g;
866
- if (h && u.sessions.get(h))
867
- g = u.sessions.get(h);
868
- else if (!h && _(s.body)) {
869
- const w = S();
870
- g = new z({
871
- sessionIdGenerator: () => w,
872
- onsessioninitialized: (T) => {
873
- u.sessions.set(T, g);
1086
+ const u = s.headers["mcp-session-id"];
1087
+ let f;
1088
+ if (u && c.sessions.get(u))
1089
+ f = c.sessions.get(u);
1090
+ else if (!u && G(s.body)) {
1091
+ await this.drainExistingSessions(c.sessions), await this.disconnectServer(c.server);
1092
+ const v = S();
1093
+ f = new Q({
1094
+ sessionIdGenerator: () => v,
1095
+ onsessioninitialized: (b) => {
1096
+ c.sessions.set(b, f);
874
1097
  }
875
- });
1098
+ }), f.onclose = () => {
1099
+ f?.sessionId && c.sessions.delete(f.sessionId);
1100
+ };
876
1101
  try {
877
- await u.server.connect(g);
1102
+ await c.server.connect(f);
878
1103
  } catch {
879
- return r.code(500), {
1104
+ return o.code(500), {
880
1105
  jsonrpc: "2.0",
881
1106
  error: { code: -32603, message: "Error initializing server." },
882
1107
  id: null
883
1108
  };
884
1109
  }
885
- g.onclose = () => {
886
- g?.sessionId && u.sessions.delete(g.sessionId);
887
- };
888
1110
  } else
889
- return r.code(400), {
1111
+ return o.code(400), {
890
1112
  jsonrpc: "2.0",
891
1113
  error: { code: -32e3, message: "Session not found or expired" },
892
1114
  id: null
893
1115
  };
894
- return await g.handleRequest(
895
- s.raw,
896
- r.raw,
897
- s.body
898
- ), r;
1116
+ return await f.handleRequest(s.raw, o.raw, s.body), o;
899
1117
  }
900
- ), e.get(`${t}/mcp`, async (s, r) => {
901
- const i = s.headers["mcp-client-id"]?.trim(), n = i && i.length > 0 ? i : "";
902
- if (!n)
903
- return r.code(400), "Missing mcp-client-id";
904
- const l = this.clientCache.get(n);
1118
+ );
1119
+ }
1120
+ /**
1121
+ * @param app - Fastify instance
1122
+ * @param base - Base path for routes
1123
+ */
1124
+ registerMcpGetEndpoint(e, t) {
1125
+ e.get(`${t}/mcp`, async (s, o) => {
1126
+ const n = s.headers["mcp-client-id"]?.trim(), i = n && n.length > 0 ? n : "";
1127
+ if (!i)
1128
+ return o.code(400), "Missing mcp-client-id";
1129
+ const { cacheKey: a } = this.resolveSessionContext(s, i), l = this.clientCache.get(a);
905
1130
  if (!l)
906
- return r.code(400), "Invalid or expired client";
1131
+ return o.code(400), "Invalid or expired client";
907
1132
  const c = s.headers["mcp-session-id"];
908
1133
  if (!c)
909
- return r.code(400), "Missing mcp-session-id";
910
- const a = l.sessions.get(c);
911
- return a ? (await a.handleRequest(s.raw, r.raw), r) : (r.code(400), "Invalid or expired session ID");
912
- }), e.delete(
1134
+ return o.code(400), "Missing mcp-session-id";
1135
+ const u = l.sessions.get(c);
1136
+ return u ? (await u.handleRequest(s.raw, o.raw), o) : (o.code(400), "Invalid or expired session ID");
1137
+ });
1138
+ }
1139
+ /**
1140
+ * @param app - Fastify instance
1141
+ * @param base - Base path for routes
1142
+ */
1143
+ registerMcpDeleteEndpoint(e, t) {
1144
+ e.delete(
913
1145
  `${t}/mcp`,
914
- async (s, r) => {
915
- const i = s.headers["mcp-client-id"]?.trim(), n = i && i.length > 0 ? i : "", l = s.headers["mcp-session-id"];
916
- if (!n || !l)
917
- return r.code(400), {
1146
+ async (s, o) => {
1147
+ const n = s.headers["mcp-client-id"]?.trim(), i = n && n.length > 0 ? n : "", a = s.headers["mcp-session-id"];
1148
+ if (!i || !a)
1149
+ return o.code(400), {
918
1150
  jsonrpc: "2.0",
919
1151
  error: {
920
1152
  code: -32600,
@@ -922,59 +1154,79 @@ class he {
922
1154
  },
923
1155
  id: null
924
1156
  };
925
- const c = this.clientCache.get(n), a = c?.sessions.get(l);
926
- if (!c || !a)
927
- return r.code(404), {
1157
+ const { cacheKey: l } = this.resolveSessionContext(s, i), c = this.clientCache.get(l), u = c?.sessions.get(a);
1158
+ if (!c || !u)
1159
+ return o.code(404), {
928
1160
  jsonrpc: "2.0",
929
1161
  error: { code: -32e3, message: "Session not found or expired" },
930
1162
  id: null
931
1163
  };
932
1164
  try {
933
- if (typeof a.close == "function")
934
- try {
935
- await a.close();
936
- } catch {
937
- }
1165
+ await u.close();
1166
+ } catch {
938
1167
  } finally {
939
- a?.sessionId ? c.sessions.delete(a.sessionId) : c.sessions.delete(l);
1168
+ u?.sessionId ? c.sessions.delete(u.sessionId) : c.sessions.delete(a);
940
1169
  }
941
- return r.code(204).send(), r;
1170
+ return o.code(204).send(), o;
942
1171
  }
943
- ), this.options.customEndpoints && this.options.customEndpoints.length > 0 && V(e, t, this.options.customEndpoints), this.options.app || await e.listen({ host: this.options.host, port: this.options.port }), this.app = e;
1172
+ );
944
1173
  }
945
- /**
946
- * Stops the Fastify server and cleans up all resources.
947
- * Closes all client sessions and clears the cache.
948
- */
949
1174
  async stop() {
950
1175
  this.app && (this.clientCache.stop(!0), this.options.app || await this.app.close(), this.app = null);
951
1176
  }
952
1177
  /**
953
- * Cleans up resources associated with a client bundle.
954
- * Closes all sessions within the bundle.
1178
+ * Closes all active sessions and clears the session map so the server is
1179
+ * free to accept a new connection. Required for SDK 1.26+, which throws
1180
+ * "Already connected" when `connect()` is called while a transport is
1181
+ * still attached. Handles unclean client disconnects followed by re-init.
1182
+ *
1183
+ * The map is cleared before closing so that `onclose` handlers fired by
1184
+ * `transport.close()` do not attempt double-deletion.
1185
+ *
1186
+ * @param sessions - The client's active session map to drain
1187
+ */
1188
+ async drainExistingSessions(e) {
1189
+ if (e.size === 0) return;
1190
+ const t = Array.from(e.values());
1191
+ e.clear();
1192
+ for (const s of t)
1193
+ try {
1194
+ await s.close();
1195
+ } catch {
1196
+ }
1197
+ }
1198
+ /**
1199
+ * Disconnects the server from its current transport so that `Protocol._transport`
1200
+ * is cleared before a new connection is established.
1201
+ *
1202
+ * `drainExistingSessions` handles same-bundle reconnects (sessions in the map).
1203
+ * This method handles the STATIC-mode cross-client case: a different client's
1204
+ * bundle has an empty sessions map, but the shared server is still attached to
1205
+ * the previous client's transport because `StreamableHTTPClientTransport.close()`
1206
+ * does not send DELETE—it only aborts connections.
1207
+ *
1208
+ * @param server - The MCP server to disconnect from its current transport
1209
+ */
1210
+ async disconnectServer(e) {
1211
+ try {
1212
+ await e.close();
1213
+ } catch {
1214
+ }
1215
+ }
1216
+ /**
955
1217
  * @param bundle - The client bundle to clean up
956
- * @private
957
1218
  */
958
1219
  cleanupBundle(e) {
959
1220
  for (const [t, s] of e.sessions.entries())
960
- try {
961
- typeof s.close == "function" && s.close().catch((r) => {
962
- console.warn(`Error closing session ${t}:`, r);
963
- });
964
- } catch (r) {
965
- console.warn(`Error closing session ${t}:`, r);
966
- }
1221
+ s.close().catch((o) => {
1222
+ console.warn(`Error closing session ${t}:`, o);
1223
+ });
967
1224
  e.sessions.clear();
968
1225
  }
969
1226
  /**
970
- * Resolves the session context and generates a cache key for the request.
971
- * If a session context resolver is configured, it extracts query parameters
972
- * and merges session-specific context with the base context.
973
- *
974
1227
  * @param req - The Fastify request
975
1228
  * @param clientId - The client identifier
976
1229
  * @returns Object with cache key and merged context
977
- * @private
978
1230
  */
979
1231
  resolveSessionContext(e, t) {
980
1232
  if (!this.sessionContextResolver)
@@ -986,45 +1238,38 @@ class he {
986
1238
  clientId: t,
987
1239
  headers: this.extractHeaders(e),
988
1240
  query: this.extractQuery(e)
989
- }, r = this.sessionContextResolver.resolve(
1241
+ }, o = this.sessionContextResolver.resolve(
990
1242
  s,
991
1243
  this.baseContext
992
1244
  );
993
1245
  return {
994
- cacheKey: r.cacheKeySuffix === "default" ? t : `${t}:${r.cacheKeySuffix}`,
995
- mergedContext: r.context
1246
+ cacheKey: o.cacheKeySuffix === "default" ? t : `${t}:${o.cacheKeySuffix}`,
1247
+ mergedContext: o.context
996
1248
  };
997
1249
  }
998
1250
  /**
999
- * Extracts headers from a Fastify request as a Record.
1000
- * Normalizes header names to lowercase.
1001
- *
1002
1251
  * @param req - The Fastify request
1003
1252
  * @returns Headers as a string record
1004
- * @private
1005
1253
  */
1006
1254
  extractHeaders(e) {
1007
1255
  const t = {};
1008
- for (const [s, r] of Object.entries(e.headers))
1009
- typeof r == "string" ? t[s.toLowerCase()] = r : Array.isArray(r) && r.length > 0 && (t[s.toLowerCase()] = r[0]);
1256
+ for (const [s, o] of Object.entries(e.headers))
1257
+ typeof o == "string" ? t[s.toLowerCase()] = o : Array.isArray(o) && o.length > 0 && (t[s.toLowerCase()] = o[0]);
1010
1258
  return t;
1011
1259
  }
1012
1260
  /**
1013
- * Extracts query parameters from a Fastify request as a Record.
1014
- *
1015
1261
  * @param req - The Fastify request
1016
1262
  * @returns Query parameters as a string record
1017
- * @private
1018
1263
  */
1019
1264
  extractQuery(e) {
1020
1265
  const t = {}, s = e.query;
1021
1266
  if (s && typeof s == "object")
1022
- for (const [r, i] of Object.entries(s))
1023
- typeof i == "string" && (t[r] = i);
1267
+ for (const [o, n] of Object.entries(s))
1268
+ typeof n == "string" && (t[o] = n);
1024
1269
  return t;
1025
1270
  }
1026
1271
  }
1027
- class fe {
1272
+ class k {
1028
1273
  constructor(e) {
1029
1274
  d(this, "config");
1030
1275
  d(this, "queryParamName");
@@ -1033,9 +1278,27 @@ class fe {
1033
1278
  d(this, "mergeStrategy");
1034
1279
  this.config = e, this.queryParamName = e.queryParam?.name ?? "config", this.encoding = e.queryParam?.encoding ?? "base64", this.allowedKeys = e.queryParam?.allowedKeys ? new Set(e.queryParam.allowedKeys) : null, this.mergeStrategy = e.merge ?? "shallow";
1035
1280
  }
1281
+ static builder() {
1282
+ const e = {}, t = {
1283
+ enabled(s) {
1284
+ return e.enabled = s, t;
1285
+ },
1286
+ queryParam(s) {
1287
+ return e.queryParam = s, t;
1288
+ },
1289
+ contextResolver(s) {
1290
+ return e.contextResolver = s, t;
1291
+ },
1292
+ merge(s) {
1293
+ return e.merge = s, t;
1294
+ },
1295
+ build() {
1296
+ return new k(e);
1297
+ }
1298
+ };
1299
+ return t;
1300
+ }
1036
1301
  /**
1037
- * Resolves the session context for a request.
1038
- *
1039
1302
  * @param request - The request context (clientId, headers, query)
1040
1303
  * @param baseContext - The base context from server configuration
1041
1304
  * @returns The resolved context and cache key suffix
@@ -1047,34 +1310,48 @@ class fe {
1047
1310
  cacheKeySuffix: "default"
1048
1311
  };
1049
1312
  const s = this.parseQueryConfig(e.query);
1050
- if (this.config.contextResolver)
1051
- try {
1052
- return {
1053
- context: this.config.contextResolver(
1054
- e,
1055
- t,
1056
- s
1057
- ),
1058
- cacheKeySuffix: this.generateCacheKeySuffix(s)
1059
- };
1060
- } catch {
1061
- return {
1062
- context: t,
1063
- cacheKeySuffix: "default"
1064
- };
1065
- }
1313
+ return this.config.contextResolver ? this.resolveWithCustomResolver(e, t, s) : this.resolveWithDefaultMerge(t, s);
1314
+ }
1315
+ /**
1316
+ * @param request - The request context
1317
+ * @param baseContext - The base context from server configuration
1318
+ * @param parsedConfig - The parsed query parameter config
1319
+ * @returns The resolved context and cache key suffix
1320
+ */
1321
+ resolveWithCustomResolver(e, t, s) {
1322
+ const o = this.config.contextResolver;
1323
+ if (!o)
1324
+ return { context: t, cacheKeySuffix: "default" };
1325
+ try {
1326
+ return {
1327
+ context: o(
1328
+ e,
1329
+ t,
1330
+ s
1331
+ ),
1332
+ cacheKeySuffix: this.generateCacheKeySuffix(s)
1333
+ };
1334
+ } catch {
1335
+ return {
1336
+ context: t,
1337
+ cacheKeySuffix: "default"
1338
+ };
1339
+ }
1340
+ }
1341
+ /**
1342
+ * @param baseContext - The base context from server configuration
1343
+ * @param parsedConfig - The parsed query parameter config
1344
+ * @returns The merged context and cache key suffix
1345
+ */
1346
+ resolveWithDefaultMerge(e, t) {
1066
1347
  return {
1067
- context: this.mergeContexts(t, s),
1068
- cacheKeySuffix: this.generateCacheKeySuffix(s)
1348
+ context: this.mergeContexts(e, t),
1349
+ cacheKeySuffix: this.generateCacheKeySuffix(t)
1069
1350
  };
1070
1351
  }
1071
1352
  /**
1072
- * Parses the session config from query parameters.
1073
- * Returns empty object on parse failure (fail secure).
1074
- *
1075
1353
  * @param query - Query parameters from the request
1076
1354
  * @returns Parsed and filtered config object
1077
- * @private
1078
1355
  */
1079
1356
  parseQueryConfig(e) {
1080
1357
  const t = e[this.queryParamName];
@@ -1083,19 +1360,15 @@ class fe {
1083
1360
  try {
1084
1361
  let s;
1085
1362
  this.encoding === "base64" ? s = Buffer.from(t, "base64").toString("utf-8") : s = t;
1086
- const r = JSON.parse(s);
1087
- return typeof r != "object" || r === null || Array.isArray(r) ? {} : this.filterAllowedKeys(r);
1363
+ const o = JSON.parse(s);
1364
+ return typeof o != "object" || o === null || Array.isArray(o) ? {} : this.filterAllowedKeys(o);
1088
1365
  } catch {
1089
1366
  return {};
1090
1367
  }
1091
1368
  }
1092
1369
  /**
1093
- * Filters the parsed config to only include allowed keys.
1094
- * If no allowedKeys whitelist is configured, returns the full object.
1095
- *
1096
1370
  * @param parsed - The parsed config object
1097
1371
  * @returns Filtered config with only allowed keys
1098
- * @private
1099
1372
  */
1100
1373
  filterAllowedKeys(e) {
1101
1374
  if (!this.allowedKeys)
@@ -1106,12 +1379,9 @@ class fe {
1106
1379
  return t;
1107
1380
  }
1108
1381
  /**
1109
- * Merges the base context with the session config.
1110
- *
1111
1382
  * @param baseContext - The base context from server configuration
1112
1383
  * @param sessionConfig - The parsed session config
1113
1384
  * @returns Merged context
1114
- * @private
1115
1385
  */
1116
1386
  mergeContexts(e, t) {
1117
1387
  return Object.keys(t).length === 0 ? e : typeof e != "object" || e === null || Array.isArray(e) ? t : this.mergeStrategy === "deep" ? this.deepMerge(
@@ -1123,73 +1393,65 @@ class fe {
1123
1393
  };
1124
1394
  }
1125
1395
  /**
1126
- * Performs a deep merge of two objects.
1127
- * Session config values override base context values.
1128
- *
1129
1396
  * @param base - The base object
1130
1397
  * @param override - The override object
1131
1398
  * @returns Deep merged object
1132
- * @private
1133
1399
  */
1134
1400
  deepMerge(e, t) {
1135
1401
  const s = { ...e };
1136
- for (const [r, i] of Object.entries(t)) {
1137
- const n = s[r];
1138
- typeof i == "object" && i !== null && !Array.isArray(i) && typeof n == "object" && n !== null && !Array.isArray(n) ? s[r] = this.deepMerge(
1139
- n,
1140
- i
1141
- ) : s[r] = i;
1402
+ for (const [o, n] of Object.entries(t)) {
1403
+ const i = s[o];
1404
+ typeof n == "object" && n !== null && !Array.isArray(n) && typeof i == "object" && i !== null && !Array.isArray(i) ? s[o] = this.deepMerge(
1405
+ i,
1406
+ n
1407
+ ) : s[o] = n;
1142
1408
  }
1143
1409
  return s;
1144
1410
  }
1145
1411
  /**
1146
- * Generates a deterministic cache key suffix based on the session config.
1147
- * Returns 'default' when no session config is present.
1148
- *
1149
1412
  * @param sessionConfig - The parsed session config
1150
1413
  * @returns Hash string or 'default'
1151
- * @private
1152
1414
  */
1153
1415
  generateCacheKeySuffix(e) {
1154
1416
  if (Object.keys(e).length === 0)
1155
1417
  return "default";
1156
1418
  const t = Object.keys(e).sort(), s = {};
1157
- for (const i of t)
1158
- s[i] = e[i];
1159
- const r = JSON.stringify(s);
1160
- return ae("sha256").update(r).digest("hex").slice(0, 16);
1419
+ for (const n of t)
1420
+ s[n] = e[n];
1421
+ const o = JSON.stringify(s);
1422
+ return Te("sha256").update(o).digest("hex").slice(0, 16);
1161
1423
  }
1162
1424
  }
1163
- function K(o) {
1164
- me(o), ye(o), ge(o), pe(o), ve(o);
1425
+ function X(r) {
1426
+ Ee(r), Ce(r), Ae(r), Pe(r), Me(r);
1165
1427
  }
1166
- function me(o) {
1167
- if (!o || typeof o != "object")
1428
+ function Ee(r) {
1429
+ if (!r || typeof r != "object")
1168
1430
  throw new Error(
1169
1431
  "Session context configuration must be an object"
1170
1432
  );
1171
1433
  }
1172
- function ye(o) {
1173
- if (o.enabled !== void 0 && typeof o.enabled != "boolean")
1434
+ function Ce(r) {
1435
+ if (r.enabled !== void 0 && typeof r.enabled != "boolean")
1174
1436
  throw new Error(
1175
- `enabled must be a boolean, got ${typeof o.enabled}`
1437
+ `enabled must be a boolean, got ${typeof r.enabled}`
1176
1438
  );
1177
1439
  }
1178
- function ge(o) {
1179
- if (o.queryParam !== void 0) {
1180
- if (typeof o.queryParam != "object" || o.queryParam === null)
1440
+ function Ae(r) {
1441
+ if (r.queryParam !== void 0) {
1442
+ if (typeof r.queryParam != "object" || r.queryParam === null)
1181
1443
  throw new Error("queryParam must be an object");
1182
- if (o.queryParam.name !== void 0 && (typeof o.queryParam.name != "string" || o.queryParam.name.length === 0))
1444
+ if (r.queryParam.name !== void 0 && (typeof r.queryParam.name != "string" || r.queryParam.name.length === 0))
1183
1445
  throw new Error("queryParam.name must be a non-empty string");
1184
- if (o.queryParam.encoding !== void 0 && o.queryParam.encoding !== "base64" && o.queryParam.encoding !== "json")
1446
+ if (r.queryParam.encoding !== void 0 && r.queryParam.encoding !== "base64" && r.queryParam.encoding !== "json")
1185
1447
  throw new Error(
1186
- `Invalid queryParam.encoding: "${o.queryParam.encoding}". Must be "base64" or "json"`
1448
+ `Invalid queryParam.encoding: "${r.queryParam.encoding}". Must be "base64" or "json"`
1187
1449
  );
1188
- if (o.queryParam.allowedKeys !== void 0) {
1189
- if (!Array.isArray(o.queryParam.allowedKeys))
1450
+ if (r.queryParam.allowedKeys !== void 0) {
1451
+ if (!Array.isArray(r.queryParam.allowedKeys))
1190
1452
  throw new Error("queryParam.allowedKeys must be an array of strings");
1191
- for (let e = 0; e < o.queryParam.allowedKeys.length; e++) {
1192
- const t = o.queryParam.allowedKeys[e];
1453
+ for (let e = 0; e < r.queryParam.allowedKeys.length; e++) {
1454
+ const t = r.queryParam.allowedKeys[e];
1193
1455
  if (typeof t != "string" || t.length === 0)
1194
1456
  throw new Error(
1195
1457
  `queryParam.allowedKeys[${e}] must be a non-empty string`
@@ -1198,172 +1460,244 @@ function ge(o) {
1198
1460
  }
1199
1461
  }
1200
1462
  }
1201
- function pe(o) {
1202
- if (o.contextResolver !== void 0 && typeof o.contextResolver != "function")
1463
+ function Pe(r) {
1464
+ if (r.contextResolver !== void 0 && typeof r.contextResolver != "function")
1203
1465
  throw new Error(
1204
1466
  "contextResolver must be a function: (request, baseContext, parsedQueryConfig?) => unknown"
1205
1467
  );
1206
1468
  }
1207
- function ve(o) {
1208
- if (o.merge !== void 0 && o.merge !== "shallow" && o.merge !== "deep")
1469
+ function Me(r) {
1470
+ if (r.merge !== void 0 && r.merge !== "shallow" && r.merge !== "deep")
1209
1471
  throw new Error(
1210
- `Invalid merge strategy: "${o.merge}". Must be "shallow" or "deep"`
1472
+ `Invalid merge strategy: "${r.merge}". Must be "shallow" or "deep"`
1211
1473
  );
1212
1474
  }
1213
- const we = v.object({
1214
- mode: v.enum(["DYNAMIC", "STATIC"]).optional(),
1215
- toolsets: v.union([v.array(v.string()), v.literal("ALL")]).optional()
1475
+ const Ie = g.object({
1476
+ mode: g.enum(["DYNAMIC", "STATIC"]).optional(),
1477
+ toolsets: g.union([g.array(g.string()), g.literal("ALL")]).optional()
1216
1478
  }).strict();
1217
- async function De(o) {
1218
- if (o.startup)
1219
- try {
1220
- we.parse(o.startup);
1221
- } catch (a) {
1222
- if (a instanceof v.ZodError) {
1223
- const u = a.format();
1224
- throw new Error(
1225
- `Invalid startup configuration:
1226
- ${JSON.stringify(u, null, 2)}
1479
+ function $e(r) {
1480
+ try {
1481
+ Ie.parse(r);
1482
+ } catch (e) {
1483
+ if (e instanceof g.ZodError) {
1484
+ const t = e.format();
1485
+ throw new Error(
1486
+ `Invalid startup configuration:
1487
+ ${JSON.stringify(t, null, 2)}
1227
1488
 
1228
1489
  Hint: Common mistake - use "toolsets" not "initialToolsets"`
1229
- );
1230
- }
1231
- throw a;
1490
+ );
1232
1491
  }
1233
- const e = o.startup?.mode ?? "DYNAMIC";
1234
- let t;
1235
- if (o.sessionContext && (K(o.sessionContext), t = new fe(o.sessionContext), e === "STATIC" && o.sessionContext.enabled !== !1 && console.warn(
1236
- "sessionContext has limited effect in STATIC mode: all clients share the same server instance with base context. Use DYNAMIC mode for per-session context isolation."
1237
- )), typeof o.createServer != "function")
1238
- throw new Error("createMcpServer: `createServer` (factory) is required");
1239
- const s = o.createServer(), r = (a) => typeof a?.server?.notification == "function", i = (a) => typeof a?.notifyToolsListChanged == "function", n = async (a) => {
1492
+ throw e;
1493
+ }
1494
+ }
1495
+ function Re() {
1496
+ const r = (t) => typeof t?.server?.notification == "function", e = (t) => typeof t?.notifyToolsListChanged == "function";
1497
+ return async (t) => {
1240
1498
  try {
1241
- if (r(a)) {
1242
- await a.server.notification({
1499
+ if (r(t)) {
1500
+ await t.server.notification({
1243
1501
  method: "notifications/tools/list_changed"
1244
1502
  });
1245
1503
  return;
1246
1504
  }
1247
- i(a) && await a.notifyToolsListChanged();
1248
- } catch (u) {
1249
- if ((u instanceof Error ? u.message : String(u)) === "Not connected")
1505
+ e(t) && await t.notifyToolsListChanged();
1506
+ } catch (s) {
1507
+ if ((s instanceof Error ? s.message : String(s)) === "Not connected")
1250
1508
  return;
1251
- console.warn("Failed to send tools list changed notification:", u);
1509
+ console.warn("Failed to send tools list changed notification:", s);
1252
1510
  }
1253
- }, l = new C({
1254
- server: s,
1255
- catalog: o.catalog,
1256
- moduleLoaders: o.moduleLoaders,
1257
- exposurePolicy: o.exposurePolicy,
1258
- context: o.context,
1259
- notifyToolsListChanged: async () => n(s),
1260
- startup: o.startup,
1261
- registerMetaTools: o.registerMetaTools !== void 0 ? o.registerMetaTools : e === "DYNAMIC"
1262
- });
1263
- e === "STATIC" && await l.ensureReady();
1264
- const c = new he(
1265
- l.getManager(),
1266
- (a) => {
1267
- const u = a ?? o.context;
1268
- if (e === "STATIC")
1269
- return { server: s, orchestrator: l };
1270
- const h = o.createServer(), g = new C({
1271
- server: h,
1272
- catalog: o.catalog,
1273
- moduleLoaders: o.moduleLoaders,
1274
- exposurePolicy: o.exposurePolicy,
1275
- context: u,
1276
- notifyToolsListChanged: async () => n(h),
1277
- startup: o.startup,
1278
- registerMetaTools: o.registerMetaTools !== void 0 ? o.registerMetaTools : e === "DYNAMIC"
1279
- });
1280
- return { server: h, orchestrator: g };
1281
- },
1282
- o.http,
1283
- o.configSchema,
1511
+ };
1512
+ }
1513
+ function Le(r, e) {
1514
+ return r !== void 0 ? r : e === "DYNAMIC";
1515
+ }
1516
+ async function nt(r) {
1517
+ je(r);
1518
+ const e = r.startup?.mode ?? "DYNAMIC", t = Le(r.registerMetaTools, e), s = Ne(r, e), o = Re(), n = r.createServer(), i = ee(
1519
+ n,
1520
+ r,
1521
+ e,
1522
+ t,
1523
+ o
1524
+ );
1525
+ e === "STATIC" && await i.ensureReady();
1526
+ const a = Oe(
1527
+ r,
1528
+ e,
1529
+ n,
1530
+ i,
1284
1531
  t,
1285
- o.context
1532
+ o
1533
+ ), l = ke(
1534
+ r,
1535
+ i.getManager(),
1536
+ a,
1537
+ s
1286
1538
  );
1287
1539
  return {
1288
- server: s,
1289
- start: async () => {
1290
- await c.start();
1291
- },
1292
- close: async () => {
1293
- await c.stop();
1294
- }
1540
+ server: n,
1541
+ start: () => l.start(),
1542
+ close: () => l.stop()
1543
+ };
1544
+ }
1545
+ function je(r) {
1546
+ if (r.startup && $e(r.startup), typeof r.createServer != "function")
1547
+ throw new Error("createMcpServer: `createServer` (factory) is required");
1548
+ }
1549
+ function Ne(r, e) {
1550
+ if (!r.sessionContext) return;
1551
+ X(r.sessionContext);
1552
+ const t = k.builder().enabled(r.sessionContext.enabled ?? !0).queryParam(r.sessionContext.queryParam).contextResolver(r.sessionContext.contextResolver).merge(r.sessionContext.merge ?? "shallow").build();
1553
+ return e === "STATIC" && r.sessionContext.enabled !== !1 && console.warn(
1554
+ "sessionContext has limited effect in STATIC mode: all clients share the same server instance with base context. Use DYNAMIC mode for per-session context isolation."
1555
+ ), t;
1556
+ }
1557
+ function ee(r, e, t, s, o, n) {
1558
+ const i = A.builder().server(r).catalog(e.catalog).moduleLoaders(e.moduleLoaders ?? {}).context(n !== void 0 ? n : e.context).notifyToolsListChanged(async () => o(r)).registerMetaTools(s);
1559
+ return e.exposurePolicy && i.exposurePolicy(e.exposurePolicy), e.startup && i.startup(e.startup), i.build();
1560
+ }
1561
+ function Oe(r, e, t, s, o, n) {
1562
+ return (i) => {
1563
+ if (e === "STATIC")
1564
+ return { server: t, orchestrator: s };
1565
+ const a = i ?? r.context, l = r.createServer(), c = ee(
1566
+ l,
1567
+ r,
1568
+ e,
1569
+ o,
1570
+ n,
1571
+ a
1572
+ );
1573
+ return { server: l, orchestrator: c };
1295
1574
  };
1296
1575
  }
1297
- function Te(o) {
1298
- be(o), Se(o), xe(o), Ae(o);
1576
+ function ke(r, e, t, s) {
1577
+ const o = O.builder().defaultManager(e).createBundle(t).host(r.http?.host ?? "0.0.0.0").port(r.http?.port ?? 3e3).basePath(r.http?.basePath ?? "/").cors(r.http?.cors ?? !0).logger(r.http?.logger ?? !1);
1578
+ return r.http?.app && o.app(r.http.app), r.http?.customEndpoints && o.customEndpoints(r.http.customEndpoints), r.configSchema && o.configSchema(r.configSchema), s && o.sessionContextResolver(s), r.context !== void 0 && o.baseContext(r.context), o.build();
1299
1579
  }
1300
- function be(o) {
1301
- if (!o || typeof o != "object")
1580
+ function De(r) {
1581
+ ze(r), qe(r), Fe(r), _e(r);
1582
+ }
1583
+ function ze(r) {
1584
+ if (!r || typeof r != "object")
1302
1585
  throw new Error(
1303
1586
  "Permission configuration is required for createPermissionBasedMcpServer"
1304
1587
  );
1305
1588
  }
1306
- function Se(o) {
1307
- if (!o.source)
1589
+ function qe(r) {
1590
+ if (!r.source)
1308
1591
  throw new Error('Permission source must be either "headers" or "config"');
1309
- if (o.source !== "headers" && o.source !== "config")
1592
+ if (r.source !== "headers" && r.source !== "config")
1310
1593
  throw new Error(
1311
- `Invalid permission source: "${o.source}". Must be either "headers" or "config"`
1594
+ `Invalid permission source: "${r.source}". Must be either "headers" or "config"`
1312
1595
  );
1313
1596
  }
1314
- function xe(o) {
1315
- if (o.source === "config" && !o.staticMap && !o.resolver)
1597
+ function Fe(r) {
1598
+ if (r.source === "config" && !r.staticMap && !r.resolver)
1316
1599
  throw new Error(
1317
1600
  "Config-based permissions require at least one of: staticMap or resolver function"
1318
1601
  );
1319
1602
  }
1320
- function Ae(o) {
1321
- if (o.staticMap !== void 0) {
1322
- if (typeof o.staticMap != "object" || o.staticMap === null)
1603
+ function _e(r) {
1604
+ if (r.staticMap !== void 0) {
1605
+ if (typeof r.staticMap != "object" || r.staticMap === null)
1323
1606
  throw new Error(
1324
1607
  "staticMap must be an object mapping client IDs to toolset arrays"
1325
1608
  );
1326
- Ce(o.staticMap);
1609
+ Ke(r.staticMap);
1327
1610
  }
1328
- if (o.resolver !== void 0 && typeof o.resolver != "function")
1611
+ if (r.resolver !== void 0 && typeof r.resolver != "function")
1329
1612
  throw new Error(
1330
1613
  "resolver must be a synchronous function: (clientId: string) => string[]"
1331
1614
  );
1332
- if (o.defaultPermissions !== void 0 && !Array.isArray(o.defaultPermissions))
1615
+ if (r.defaultPermissions !== void 0 && !Array.isArray(r.defaultPermissions))
1333
1616
  throw new Error("defaultPermissions must be an array of toolset names");
1334
- if (o.headerName !== void 0 && (typeof o.headerName != "string" || o.headerName.length === 0))
1617
+ if (r.headerName !== void 0 && (typeof r.headerName != "string" || r.headerName.length === 0))
1335
1618
  throw new Error("headerName must be a non-empty string");
1336
1619
  }
1337
- function Ce(o) {
1338
- for (const [e, t] of Object.entries(o))
1620
+ function Ke(r) {
1621
+ for (const [e, t] of Object.entries(r))
1339
1622
  if (!Array.isArray(t))
1340
1623
  throw new Error(
1341
1624
  `staticMap value for client "${e}" must be an array of toolset names`
1342
1625
  );
1343
1626
  }
1344
- var p, H, B, Y, U, W;
1345
- class Ee {
1346
- /**
1347
- * Creates a new PermissionResolver instance.
1348
- * @param config - The permission configuration defining how permissions are resolved
1349
- */
1627
+ function Be(r, e) {
1628
+ return async (t) => {
1629
+ const s = e.resolvePermissions(
1630
+ t.clientId,
1631
+ t.headers
1632
+ ), o = r(s), n = o.orchestrator.getManager(), i = [], a = [];
1633
+ if (s.length > 0) {
1634
+ const l = await n.enableToolsets(s);
1635
+ for (const c of l.results)
1636
+ c.success ? i.push(c.name) : (a.push(c.name), console.warn(
1637
+ `Failed to enable toolset '${c.name}' for client '${t.clientId}': ${c.message}`
1638
+ ));
1639
+ if (i.length === 0 && a.length > 0)
1640
+ throw new Error(
1641
+ `All requested toolsets failed to enable for client '${t.clientId}'. Requested: [${s.join(", ")}]. Check that toolset names in permissions match the catalog.`
1642
+ );
1643
+ }
1644
+ return {
1645
+ server: o.server,
1646
+ orchestrator: o.orchestrator,
1647
+ allowedToolsets: i,
1648
+ failedToolsets: a
1649
+ };
1650
+ };
1651
+ }
1652
+ function He(r) {
1653
+ if (!r) return;
1654
+ const e = {
1655
+ namespaceToolsWithSetKey: r.namespaceToolsWithSetKey
1656
+ };
1657
+ return r.allowlist !== void 0 && console.warn(
1658
+ "Permission-based servers: exposurePolicy.allowlist is ignored. Allowed toolsets are determined by client permissions."
1659
+ ), r.denylist !== void 0 && console.warn(
1660
+ "Permission-based servers: exposurePolicy.denylist is ignored. Use permission configuration to control toolset access."
1661
+ ), r.maxActiveToolsets !== void 0 && console.warn(
1662
+ "Permission-based servers: exposurePolicy.maxActiveToolsets is ignored. Toolset count is determined by client permissions."
1663
+ ), r.onLimitExceeded !== void 0 && console.warn(
1664
+ "Permission-based servers: exposurePolicy.onLimitExceeded is ignored. No toolset limits are enforced."
1665
+ ), e;
1666
+ }
1667
+ var y, te, se, re, oe, ne;
1668
+ const z = class z {
1350
1669
  constructor(e) {
1351
- A(this, p);
1670
+ x(this, y);
1352
1671
  d(this, "cache", /* @__PURE__ */ new Map());
1353
1672
  d(this, "normalizedHeaderName");
1354
1673
  this.config = e, this.normalizedHeaderName = (e.headerName || "mcp-toolset-permissions").toLowerCase();
1355
1674
  }
1675
+ static builder() {
1676
+ const e = {}, t = {
1677
+ source(s) {
1678
+ return e.source = s, t;
1679
+ },
1680
+ headerName(s) {
1681
+ return e.headerName = s, t;
1682
+ },
1683
+ staticMap(s) {
1684
+ return e.staticMap = s, t;
1685
+ },
1686
+ resolver(s) {
1687
+ return e.resolver = s, t;
1688
+ },
1689
+ defaultPermissions(s) {
1690
+ return e.defaultPermissions = s, t;
1691
+ },
1692
+ build() {
1693
+ return new z(e);
1694
+ }
1695
+ };
1696
+ return t;
1697
+ }
1356
1698
  /**
1357
- * Resolves permissions for a client based on the configured source.
1358
- * Results are cached to improve performance for subsequent requests from the same client.
1359
- * Handles all errors gracefully by returning empty permissions on failure.
1360
- *
1361
- * Note on caching: For header-based permissions, permissions are cached by clientId.
1362
- * This means subsequent requests from the same client will use cached permissions,
1363
- * even if headers change. Use invalidateCache(clientId) to force re-resolution.
1364
- *
1365
1699
  * @param clientId - The unique identifier for the client
1366
- * @param headers - Optional request headers (required for header-based permissions)
1700
+ * @param headers - Optional request headers
1367
1701
  * @returns Array of toolset names the client is allowed to access
1368
1702
  */
1369
1703
  resolvePermissions(e, t) {
@@ -1371,48 +1705,37 @@ class Ee {
1371
1705
  return this.cache.get(e);
1372
1706
  let s;
1373
1707
  try {
1374
- this.config.source === "headers" ? s = m(this, p, H).call(this, t) : s = m(this, p, Y).call(this, e), Array.isArray(s) || (console.warn(
1708
+ this.config.source === "headers" ? s = m(this, y, te).call(this, t) : s = m(this, y, re).call(this, e), Array.isArray(s) || (console.warn(
1375
1709
  `Permission resolution returned non-array for client ${e}, using empty permissions`
1376
1710
  ), s = []), s = s.filter(
1377
- (r) => typeof r == "string" && r.trim().length > 0
1711
+ (o) => typeof o == "string" && o.trim().length > 0
1378
1712
  );
1379
- } catch (r) {
1713
+ } catch (o) {
1380
1714
  console.error(
1381
1715
  `Unexpected error resolving permissions for client ${e}:`,
1382
- r
1716
+ o
1383
1717
  ), s = [];
1384
1718
  }
1385
1719
  return this.cache.set(e, s), s;
1386
1720
  }
1387
1721
  /**
1388
- * Invalidates cached permissions for a specific client.
1389
- * Call this when you know a client's permissions have changed.
1390
1722
  * @param clientId - The client ID to invalidate
1391
1723
  */
1392
1724
  invalidateCache(e) {
1393
1725
  this.cache.delete(e);
1394
1726
  }
1395
- /**
1396
- * Clears the permission cache.
1397
- * Useful for cleanup during server shutdown or when permissions need to be refreshed.
1398
- */
1399
1727
  clearCache() {
1400
1728
  this.cache.clear();
1401
1729
  }
1402
- }
1403
- p = new WeakSet(), /**
1404
- * Parses permissions from request headers.
1405
- * Extracts comma-separated toolset names from the configured header.
1406
- * Handles malformed headers gracefully by returning empty permissions.
1407
- * Uses case-insensitive header lookup per RFC 7230.
1730
+ };
1731
+ y = new WeakSet(), /**
1408
1732
  * @param headers - Request headers containing permission data
1409
- * @returns Array of toolset names from headers, or empty array if header is missing/malformed
1410
- * @private
1733
+ * @returns Array of toolset names from headers
1411
1734
  */
1412
- H = function(e) {
1735
+ te = function(e) {
1413
1736
  if (!e)
1414
1737
  return [];
1415
- const t = m(this, p, B).call(this, e, this.normalizedHeaderName);
1738
+ const t = m(this, y, se).call(this, e, this.normalizedHeaderName);
1416
1739
  if (!t)
1417
1740
  return [];
1418
1741
  try {
@@ -1424,47 +1747,37 @@ H = function(e) {
1424
1747
  ), [];
1425
1748
  }
1426
1749
  }, /**
1427
- * Finds a header value using case-insensitive key matching.
1428
- * HTTP headers are case-insensitive per RFC 7230.
1429
1750
  * @param headers - The headers object to search
1430
1751
  * @param normalizedKey - The lowercase key to search for
1431
- * @returns The header value if found, undefined otherwise
1432
- * @private
1752
+ * @returns The header value if found
1433
1753
  */
1434
- B = function(e, t) {
1754
+ se = function(e, t) {
1435
1755
  if (e[t] !== void 0)
1436
1756
  return e[t];
1437
- for (const [s, r] of Object.entries(e))
1757
+ for (const [s, o] of Object.entries(e))
1438
1758
  if (s.toLowerCase() === t)
1439
- return r;
1759
+ return o;
1440
1760
  }, /**
1441
- * Resolves permissions from server-side configuration.
1442
- * Tries resolver function first (if provided), then falls back to static map,
1443
- * and finally to default permissions. Handles errors gracefully.
1444
1761
  * @param clientId - The unique identifier for the client
1445
1762
  * @returns Array of toolset names from configuration
1446
- * @private
1447
1763
  */
1448
- Y = function(e) {
1764
+ re = function(e) {
1449
1765
  if (this.config.resolver) {
1450
- const t = m(this, p, U).call(this, e);
1766
+ const t = m(this, y, oe).call(this, e);
1451
1767
  if (t !== null)
1452
1768
  return t;
1453
1769
  }
1454
1770
  if (this.config.staticMap) {
1455
- const t = m(this, p, W).call(this, e);
1771
+ const t = m(this, y, ne).call(this, e);
1456
1772
  if (t !== null)
1457
1773
  return t;
1458
1774
  }
1459
1775
  return this.config.defaultPermissions || [];
1460
1776
  }, /**
1461
- * Attempts to resolve permissions using the configured resolver function.
1462
- * Handles errors gracefully and returns null on failure to allow fallback.
1463
1777
  * @param clientId - The unique identifier for the client
1464
- * @returns Array of toolset names if successful, null if resolver fails or returns invalid data
1465
- * @private
1778
+ * @returns Array of toolset names if successful, null if resolver fails
1466
1779
  */
1467
- U = function(e) {
1780
+ oe = function(e) {
1468
1781
  try {
1469
1782
  const t = this.config.resolver(e);
1470
1783
  return Array.isArray(t) ? t : (console.warn(
@@ -1477,61 +1790,28 @@ U = function(e) {
1477
1790
  ), null;
1478
1791
  }
1479
1792
  }, /**
1480
- * Looks up permissions in the static map configuration.
1481
- * Returns null if client is not found to allow fallback to defaults.
1482
1793
  * @param clientId - The unique identifier for the client
1483
1794
  * @returns Array of toolset names if found, null if client not in map
1484
- * @private
1485
1795
  */
1486
- W = function(e) {
1796
+ ne = function(e) {
1487
1797
  const t = this.config.staticMap[e];
1488
1798
  return t !== void 0 ? Array.isArray(t) ? t : [] : null;
1489
1799
  };
1490
- function Pe(o, e) {
1491
- return async (t) => {
1492
- const s = e.resolvePermissions(
1493
- t.clientId,
1494
- t.headers
1495
- ), r = o(s), i = r.orchestrator.getManager(), n = [], l = [];
1496
- if (s.length > 0) {
1497
- const c = await i.enableToolsets(s);
1498
- for (const a of c.results)
1499
- a.success ? n.push(a.name) : (l.push(a.name), console.warn(
1500
- `Failed to enable toolset '${a.name}' for client '${t.clientId}': ${a.message}`
1501
- ));
1502
- if (n.length === 0 && l.length > 0)
1503
- throw new Error(
1504
- `All requested toolsets failed to enable for client '${t.clientId}'. Requested: [${s.join(", ")}]. Check that toolset names in permissions match the catalog.`
1505
- );
1506
- }
1507
- return {
1508
- server: r.server,
1509
- orchestrator: r.orchestrator,
1510
- allowedToolsets: n,
1511
- failedToolsets: l
1512
- };
1513
- };
1514
- }
1515
- var f, J, Q, G, Z, X, ee, te, se, M, oe;
1516
- class Me {
1517
- /**
1518
- * Creates a new PermissionAwareFastifyTransport instance.
1519
- * @param defaultManager - Default tool manager for status endpoints
1520
- * @param createPermissionAwareBundle - Function to create permission-aware bundles
1521
- * @param options - Transport configuration options
1522
- * @param configSchema - Optional JSON schema for configuration discovery
1523
- */
1524
- constructor(e, t, s = {}, r) {
1525
- A(this, f);
1800
+ let I = z;
1801
+ const Ve = g.string({ message: "Missing required mcp-client-id header" }).trim().min(1, "mcp-client-id header must not be empty");
1802
+ var h, ie, ae, le, ce, de, ue, he, fe, me, pe, R, ge;
1803
+ const q = class q {
1804
+ constructor(e, t, s = {}, o) {
1805
+ x(this, h);
1526
1806
  d(this, "options");
1527
1807
  d(this, "defaultManager");
1528
1808
  d(this, "createPermissionAwareBundle");
1529
1809
  d(this, "app", null);
1530
1810
  d(this, "configSchema");
1531
1811
  // Per-client server bundles and per-client session transports
1532
- d(this, "clientCache", new F({
1812
+ d(this, "clientCache", new E({
1533
1813
  onEvict: (e, t) => {
1534
- m(this, f, J).call(this, t);
1814
+ m(this, h, le).call(this, t);
1535
1815
  }
1536
1816
  }));
1537
1817
  this.defaultManager = e, this.createPermissionAwareBundle = t, this.options = {
@@ -1542,29 +1822,66 @@ class Me {
1542
1822
  logger: s.logger ?? !1,
1543
1823
  app: s.app,
1544
1824
  customEndpoints: s.customEndpoints
1545
- }, this.configSchema = r;
1825
+ }, this.configSchema = o;
1826
+ }
1827
+ static builder() {
1828
+ let e, t;
1829
+ const s = {};
1830
+ let o;
1831
+ const n = {
1832
+ defaultManager(i) {
1833
+ return e = i, n;
1834
+ },
1835
+ createPermissionAwareBundle(i) {
1836
+ return t = i, n;
1837
+ },
1838
+ host(i) {
1839
+ return s.host = i, n;
1840
+ },
1841
+ port(i) {
1842
+ return s.port = i, n;
1843
+ },
1844
+ basePath(i) {
1845
+ return s.basePath = i, n;
1846
+ },
1847
+ cors(i) {
1848
+ return s.cors = i, n;
1849
+ },
1850
+ logger(i) {
1851
+ return s.logger = i, n;
1852
+ },
1853
+ app(i) {
1854
+ return s.app = i, n;
1855
+ },
1856
+ customEndpoints(i) {
1857
+ return s.customEndpoints = i, n;
1858
+ },
1859
+ configSchema(i) {
1860
+ return o = i, n;
1861
+ },
1862
+ build() {
1863
+ return new q(e, t, s, o);
1864
+ }
1865
+ };
1866
+ return n;
1546
1867
  }
1547
- /**
1548
- * Starts the Fastify server and registers all MCP endpoints.
1549
- * Sets up routes for health checks, tool status, and MCP protocol handling.
1550
- */
1551
1868
  async start() {
1552
1869
  if (this.app) return;
1553
- const e = this.options.app ?? N({ logger: this.options.logger });
1554
- this.options.cors && await e.register(D, { origin: !0 });
1555
- const t = m(this, f, Q).call(this, this.options.basePath);
1556
- m(this, f, G).call(this, e, t), m(this, f, Z).call(this, e, t), m(this, f, X).call(this, e, t), m(this, f, ee).call(this, e, t), m(this, f, te).call(this, e, t), m(this, f, se).call(this, e, t), this.options.customEndpoints && this.options.customEndpoints.length > 0 && V(e, t, this.options.customEndpoints, {
1870
+ const e = this.options.app ?? U({ logger: this.options.logger });
1871
+ this.options.cors && await e.register(J, { origin: !0 });
1872
+ const t = m(this, h, ce).call(this, this.options.basePath);
1873
+ m(this, h, de).call(this, e, t), m(this, h, ue).call(this, e, t), m(this, h, he).call(this, e, t), m(this, h, fe).call(this, e, t), m(this, h, me).call(this, e, t), m(this, h, pe).call(this, e, t), this.options.customEndpoints && this.options.customEndpoints.length > 0 && Z(e, t, this.options.customEndpoints, {
1557
1874
  contextExtractor: async (s) => {
1558
- const r = m(this, f, M).call(this, s);
1875
+ const o = m(this, h, R).call(this, s);
1559
1876
  try {
1560
- const i = await this.createPermissionAwareBundle(r);
1877
+ const n = await this.createPermissionAwareBundle(o);
1561
1878
  return {
1562
- allowedToolsets: i.allowedToolsets,
1563
- failedToolsets: i.failedToolsets
1879
+ allowedToolsets: n.allowedToolsets,
1880
+ failedToolsets: n.failedToolsets
1564
1881
  };
1565
- } catch (i) {
1882
+ } catch (n) {
1566
1883
  return console.warn(
1567
- `Permission resolution failed for custom endpoint: ${i}`
1884
+ `Permission resolution failed for custom endpoint: ${n}`
1568
1885
  ), {
1569
1886
  allowedToolsets: [],
1570
1887
  failedToolsets: []
@@ -1573,62 +1890,57 @@ class Me {
1573
1890
  }
1574
1891
  }), this.options.app || await e.listen({ host: this.options.host, port: this.options.port }), this.app = e;
1575
1892
  }
1576
- /**
1577
- * Stops the Fastify server and cleans up all resources.
1578
- * Closes all client sessions and clears the cache.
1579
- */
1580
1893
  async stop() {
1581
1894
  this.app && (this.clientCache.stop(!0), this.options.app || await this.app.close(), this.app = null);
1582
1895
  }
1583
- }
1584
- f = new WeakSet(), /**
1585
- * Cleans up resources associated with a client bundle.
1586
- * Closes all sessions within the bundle.
1896
+ };
1897
+ h = new WeakSet(), ie = async function(e) {
1898
+ if (e.size === 0) return;
1899
+ const t = Array.from(e.values());
1900
+ e.clear();
1901
+ for (const s of t)
1902
+ try {
1903
+ await s.close();
1904
+ } catch {
1905
+ }
1906
+ }, ae = async function(e) {
1907
+ try {
1908
+ await e.close();
1909
+ } catch {
1910
+ }
1911
+ }, /**
1587
1912
  * @param bundle - The client bundle to clean up
1588
- * @private
1589
1913
  */
1590
- J = function(e) {
1914
+ le = function(e) {
1591
1915
  for (const [t, s] of e.sessions.entries())
1592
- try {
1593
- typeof s.close == "function" && s.close().catch((r) => {
1594
- console.warn(`Error closing session ${t}:`, r);
1595
- });
1596
- } catch (r) {
1597
- console.warn(`Error closing session ${t}:`, r);
1598
- }
1916
+ s.close().catch((o) => {
1917
+ console.warn(`Error closing session ${t}:`, o);
1918
+ });
1599
1919
  e.sessions.clear();
1600
1920
  }, /**
1601
- * Normalizes the base path by removing trailing slashes.
1602
1921
  * @param basePath - The base path to normalize
1603
1922
  * @returns Normalized base path without trailing slash
1604
- * @private
1605
1923
  */
1606
- Q = function(e) {
1924
+ ce = function(e) {
1607
1925
  return e.endsWith("/") ? e.slice(0, -1) : e;
1608
1926
  }, /**
1609
- * Registers the health check endpoint.
1610
1927
  * @param app - Fastify instance
1611
1928
  * @param base - Base path for routes
1612
- * @private
1613
1929
  */
1614
- G = function(e, t) {
1930
+ de = function(e, t) {
1615
1931
  e.get(`${t}/healthz`, async () => ({ ok: !0 }));
1616
1932
  }, /**
1617
- * Registers the tools status endpoint.
1618
1933
  * @param app - Fastify instance
1619
1934
  * @param base - Base path for routes
1620
- * @private
1621
1935
  */
1622
- Z = function(e, t) {
1936
+ ue = function(e, t) {
1623
1937
  e.get(`${t}/tools`, async () => this.defaultManager.getStatus());
1624
1938
  }, /**
1625
- * Registers the MCP configuration discovery endpoint.
1626
1939
  * @param app - Fastify instance
1627
1940
  * @param base - Base path for routes
1628
- * @private
1629
1941
  */
1630
- X = function(e, t) {
1631
- e.get(`${t}/.well-known/mcp-config`, async (s, r) => (r.header("Content-Type", "application/schema+json; charset=utf-8"), this.configSchema ?? {
1942
+ he = function(e, t) {
1943
+ e.get(`${t}/.well-known/mcp-config`, async (s, o) => (o.header("Content-Type", "application/schema+json; charset=utf-8"), this.configSchema ?? {
1632
1944
  $schema: "https://json-schema.org/draft/2020-12/schema",
1633
1945
  title: "MCP Session Configuration",
1634
1946
  description: "Schema for the /mcp endpoint configuration",
@@ -1639,108 +1951,106 @@ X = function(e, t) {
1639
1951
  "x-query-style": "dot+bracket"
1640
1952
  }));
1641
1953
  }, /**
1642
- * Registers the POST /mcp endpoint for JSON-RPC requests.
1643
- * Extracts client context, resolves permissions, and handles MCP protocol.
1644
1954
  * @param app - Fastify instance
1645
1955
  * @param base - Base path for routes
1646
- * @private
1647
1956
  */
1648
- ee = function(e, t) {
1957
+ fe = function(e, t) {
1649
1958
  e.post(
1650
1959
  `${t}/mcp`,
1651
- async (s, r) => {
1652
- const i = m(this, f, M).call(this, s), n = !i.clientId.startsWith("anon-");
1653
- let l = n ? this.clientCache.get(i.clientId) : null;
1654
- if (!l)
1960
+ async (s, o) => {
1961
+ const n = Ve.safeParse(
1962
+ s.headers["mcp-client-id"]
1963
+ );
1964
+ if (!n.success)
1965
+ return o.code(400), {
1966
+ jsonrpc: "2.0",
1967
+ error: { code: -32600, message: n.error.issues[0].message },
1968
+ id: null
1969
+ };
1970
+ const i = m(this, h, R).call(this, s);
1971
+ let a = this.clientCache.get(i.clientId);
1972
+ if (!a)
1655
1973
  try {
1656
1974
  const u = await this.createPermissionAwareBundle(i);
1657
1975
  u.failedToolsets.length > 0 && console.warn(
1658
1976
  `Client ${i.clientId} had ${u.failedToolsets.length} toolsets fail to enable: [${u.failedToolsets.join(", ")}]. Successfully enabled: [${u.allowedToolsets.join(", ")}]`
1659
1977
  );
1660
- const h = u.sessions;
1661
- l = {
1978
+ const f = u.sessions;
1979
+ a = {
1662
1980
  server: u.server,
1663
1981
  orchestrator: u.orchestrator,
1664
1982
  allowedToolsets: u.allowedToolsets,
1665
1983
  failedToolsets: u.failedToolsets,
1666
- sessions: h instanceof Map ? h : /* @__PURE__ */ new Map()
1667
- }, n && this.clientCache.set(i.clientId, l);
1984
+ sessions: f instanceof Map ? f : /* @__PURE__ */ new Map()
1985
+ }, this.clientCache.set(i.clientId, a);
1668
1986
  } catch (u) {
1669
1987
  return console.error(
1670
1988
  `Failed to create permission-aware bundle for client ${i.clientId}:`,
1671
1989
  u
1672
- ), r.code(403), m(this, f, oe).call(this, "Access denied");
1990
+ ), o.code(403), m(this, h, ge).call(this, "Access denied");
1673
1991
  }
1674
- const c = s.headers["mcp-session-id"];
1675
- let a;
1676
- if (c && l.sessions.get(c))
1677
- a = l.sessions.get(c);
1678
- else if (!c && _(s.body)) {
1992
+ const l = s.headers["mcp-session-id"];
1993
+ let c;
1994
+ if (l && a.sessions.get(l))
1995
+ c = a.sessions.get(l);
1996
+ else if (!l && G(s.body)) {
1997
+ await m(this, h, ie).call(this, a.sessions), await m(this, h, ae).call(this, a.server);
1679
1998
  const u = S();
1680
- a = new z({
1999
+ c = new Q({
1681
2000
  sessionIdGenerator: () => u,
1682
- onsessioninitialized: (h) => {
1683
- l.sessions.set(h, a);
2001
+ onsessioninitialized: (f) => {
2002
+ a.sessions.set(f, c);
1684
2003
  }
1685
- });
2004
+ }), c.onclose = () => {
2005
+ c?.sessionId && a.sessions.delete(c.sessionId);
2006
+ };
1686
2007
  try {
1687
- await l.server.connect(a);
2008
+ await a.server.connect(c);
1688
2009
  } catch {
1689
- return r.code(500), {
2010
+ return o.code(500), {
1690
2011
  jsonrpc: "2.0",
1691
2012
  error: { code: -32603, message: "Error initializing server." },
1692
2013
  id: null
1693
2014
  };
1694
2015
  }
1695
- a.onclose = () => {
1696
- a?.sessionId && l.sessions.delete(a.sessionId);
1697
- };
1698
2016
  } else
1699
- return r.code(400), {
2017
+ return o.code(400), {
1700
2018
  jsonrpc: "2.0",
1701
2019
  error: { code: -32e3, message: "Session not found or expired" },
1702
2020
  id: null
1703
2021
  };
1704
- return await a.handleRequest(
1705
- s.raw,
1706
- r.raw,
1707
- s.body
1708
- ), r;
2022
+ return await c.handleRequest(s.raw, o.raw, s.body), o;
1709
2023
  }
1710
2024
  );
1711
2025
  }, /**
1712
- * Registers the GET /mcp endpoint for SSE notifications.
1713
2026
  * @param app - Fastify instance
1714
2027
  * @param base - Base path for routes
1715
- * @private
1716
2028
  */
1717
- te = function(e, t) {
1718
- e.get(`${t}/mcp`, async (s, r) => {
1719
- const i = s.headers["mcp-client-id"]?.trim(), n = i && i.length > 0 ? i : "";
1720
- if (!n)
1721
- return r.code(400), "Missing mcp-client-id";
1722
- const l = this.clientCache.get(n);
2029
+ me = function(e, t) {
2030
+ e.get(`${t}/mcp`, async (s, o) => {
2031
+ const n = s.headers["mcp-client-id"]?.trim(), i = n && n.length > 0 ? n : "";
2032
+ if (!i)
2033
+ return o.code(400), "Missing mcp-client-id";
2034
+ const a = this.clientCache.get(i);
2035
+ if (!a)
2036
+ return o.code(400), "Invalid or expired client";
2037
+ const l = s.headers["mcp-session-id"];
1723
2038
  if (!l)
1724
- return r.code(400), "Invalid or expired client";
1725
- const c = s.headers["mcp-session-id"];
1726
- if (!c)
1727
- return r.code(400), "Missing mcp-session-id";
1728
- const a = l.sessions.get(c);
1729
- return a ? (await a.handleRequest(s.raw, r.raw), r) : (r.code(400), "Invalid or expired session ID");
2039
+ return o.code(400), "Missing mcp-session-id";
2040
+ const c = a.sessions.get(l);
2041
+ return c ? (await c.handleRequest(s.raw, o.raw), o) : (o.code(400), "Invalid or expired session ID");
1730
2042
  });
1731
2043
  }, /**
1732
- * Registers the DELETE /mcp endpoint for session termination.
1733
2044
  * @param app - Fastify instance
1734
2045
  * @param base - Base path for routes
1735
- * @private
1736
2046
  */
1737
- se = function(e, t) {
2047
+ pe = function(e, t) {
1738
2048
  e.delete(
1739
2049
  `${t}/mcp`,
1740
- async (s, r) => {
1741
- const i = s.headers["mcp-client-id"]?.trim(), n = i && i.length > 0 ? i : "", l = s.headers["mcp-session-id"];
1742
- if (!n || !l)
1743
- return r.code(400), {
2050
+ async (s, o) => {
2051
+ const n = s.headers["mcp-client-id"]?.trim(), i = n && n.length > 0 ? n : "", a = s.headers["mcp-session-id"];
2052
+ if (!i || !a)
2053
+ return o.code(400), {
1744
2054
  jsonrpc: "2.0",
1745
2055
  error: {
1746
2056
  code: -32600,
@@ -1748,46 +2058,37 @@ se = function(e, t) {
1748
2058
  },
1749
2059
  id: null
1750
2060
  };
1751
- const c = this.clientCache.get(n), a = c?.sessions.get(l);
1752
- if (!c || !a)
1753
- return r.code(404), {
2061
+ const l = this.clientCache.get(i), c = l?.sessions.get(a);
2062
+ if (!l || !c)
2063
+ return o.code(404), {
1754
2064
  jsonrpc: "2.0",
1755
2065
  error: { code: -32e3, message: "Session not found or expired" },
1756
2066
  id: null
1757
2067
  };
1758
2068
  try {
1759
- if (typeof a.close == "function")
1760
- try {
1761
- await a.close();
1762
- } catch {
1763
- }
2069
+ await c.close();
2070
+ } catch {
1764
2071
  } finally {
1765
- a?.sessionId ? c.sessions.delete(a.sessionId) : c.sessions.delete(l);
2072
+ c?.sessionId ? l.sessions.delete(c.sessionId) : l.sessions.delete(a);
1766
2073
  }
1767
- return r.code(204).send(), r;
2074
+ return o.code(204).send(), o;
1768
2075
  }
1769
2076
  );
1770
2077
  }, /**
1771
- * Extracts client context from the request.
1772
- * Generates anonymous client ID if not provided in headers.
1773
2078
  * @param req - Fastify request object
1774
2079
  * @returns Client request context with ID and headers
1775
- * @private
1776
2080
  */
1777
- M = function(e) {
1778
- const t = e.headers["mcp-client-id"]?.trim(), s = t && t.length > 0 ? t : `anon-${S()}`, r = {};
1779
- for (const [i, n] of Object.entries(e.headers))
1780
- typeof n == "string" && (r[i] = n);
1781
- return { clientId: s, headers: r };
2081
+ R = function(e) {
2082
+ const t = e.headers["mcp-client-id"]?.trim(), s = t && t.length > 0 ? t : `anon-${S()}`, o = {};
2083
+ for (const [n, i] of Object.entries(e.headers))
2084
+ typeof i == "string" && (o[n] = i);
2085
+ return { clientId: s, headers: o };
1782
2086
  }, /**
1783
- * Creates a safe error response that doesn't expose unauthorized toolset information.
1784
- * Used for permission-related errors to prevent information leakage.
1785
2087
  * @param message - Generic error message to return to client
1786
- * @param code - JSON-RPC error code (default: -32000 for server error)
2088
+ * @param code - JSON-RPC error code
1787
2089
  * @returns JSON-RPC error response object
1788
- * @private
1789
2090
  */
1790
- oe = function(e = "Access denied", t = -32e3) {
2091
+ ge = function(e = "Access denied", t = -32e3) {
1791
2092
  return {
1792
2093
  jsonrpc: "2.0",
1793
2094
  error: {
@@ -1797,97 +2098,64 @@ oe = function(e = "Access denied", t = -32e3) {
1797
2098
  id: null
1798
2099
  };
1799
2100
  };
1800
- function Ie(o) {
1801
- if (!o) return;
1802
- const e = {
1803
- namespaceToolsWithSetKey: o.namespaceToolsWithSetKey
2101
+ let $ = q;
2102
+ async function it(r) {
2103
+ We(r);
2104
+ const e = He(r.exposurePolicy), t = Ye(r), s = r.createServer(), o = ye(s, r, e), n = Be(
2105
+ Ue(r, e),
2106
+ t
2107
+ ), i = Je(r, o.getManager(), n);
2108
+ return {
2109
+ server: s,
2110
+ start: () => i.start(),
2111
+ close: async () => {
2112
+ try {
2113
+ await i.stop();
2114
+ } finally {
2115
+ t.clearCache();
2116
+ }
2117
+ }
1804
2118
  };
1805
- return o.allowlist !== void 0 && console.warn(
1806
- "Permission-based servers: exposurePolicy.allowlist is ignored. Allowed toolsets are determined by client permissions."
1807
- ), o.denylist !== void 0 && console.warn(
1808
- "Permission-based servers: exposurePolicy.denylist is ignored. Use permission configuration to control toolset access."
1809
- ), o.maxActiveToolsets !== void 0 && console.warn(
1810
- "Permission-based servers: exposurePolicy.maxActiveToolsets is ignored. Toolset count is determined by client permissions."
1811
- ), o.onLimitExceeded !== void 0 && console.warn(
1812
- "Permission-based servers: exposurePolicy.onLimitExceeded is ignored. No toolset limits are enforced."
1813
- ), e;
1814
2119
  }
1815
- async function ze(o) {
1816
- if (!o.permissions)
2120
+ function We(r) {
2121
+ if (!r.permissions)
1817
2122
  throw new Error(
1818
2123
  "Permission configuration is required for createPermissionBasedMcpServer. Please provide a 'permissions' field in the options."
1819
2124
  );
1820
- if (Te(o.permissions), o.sessionContext && (K(o.sessionContext), console.warn(
2125
+ if (De(r.permissions), r.sessionContext && (X(r.sessionContext), console.warn(
1821
2126
  "Session context support for permission-based servers is limited. The base context will be used for module loaders."
1822
- )), o.startup)
2127
+ )), r.startup)
1823
2128
  throw new Error(
1824
2129
  "Permission-based servers determine toolsets from client permissions. The 'startup' option is not allowed. Remove it from your configuration."
1825
2130
  );
1826
- if (typeof o.createServer != "function")
2131
+ if (typeof r.createServer != "function")
1827
2132
  throw new Error(
1828
2133
  "createPermissionBasedMcpServer: `createServer` (factory) is required"
1829
2134
  );
1830
- const e = Ie(
1831
- o.exposurePolicy
1832
- ), t = new Ee(o.permissions), s = o.createServer(), r = new C({
1833
- server: s,
1834
- catalog: o.catalog,
1835
- moduleLoaders: o.moduleLoaders,
1836
- exposurePolicy: e,
1837
- context: o.context,
1838
- notifyToolsListChanged: void 0,
1839
- // No notifications in STATIC mode
1840
- startup: { mode: "STATIC", toolsets: [] },
1841
- registerMetaTools: !1
1842
- }), i = Pe(
1843
- (l) => {
1844
- const c = o.createServer(), a = new C({
1845
- server: c,
1846
- catalog: o.catalog,
1847
- moduleLoaders: o.moduleLoaders,
1848
- exposurePolicy: e,
1849
- context: o.context,
1850
- notifyToolsListChanged: void 0,
1851
- // No notifications in STATIC mode
1852
- startup: { mode: "STATIC", toolsets: [] },
1853
- // Empty - we'll enable manually
1854
- registerMetaTools: !1
1855
- // No meta-tools - toolsets are fixed per client
1856
- });
1857
- return { server: c, orchestrator: a };
1858
- },
1859
- t
1860
- ), n = new Me(
1861
- r.getManager(),
1862
- i,
1863
- o.http,
1864
- o.configSchema
1865
- );
1866
- return {
1867
- server: s,
1868
- start: async () => {
1869
- await n.start();
1870
- },
1871
- close: async () => {
1872
- try {
1873
- await n.stop();
1874
- } finally {
1875
- t.clearCache();
1876
- }
1877
- }
1878
- };
1879
2135
  }
1880
- function _e(o) {
1881
- return o;
2136
+ function Ye(r) {
2137
+ const e = I.builder().source(r.permissions.source).headerName(r.permissions.headerName ?? "mcp-toolset-permissions").staticMap(r.permissions.staticMap ?? {}).defaultPermissions(r.permissions.defaultPermissions ?? []);
2138
+ return r.permissions.resolver && e.resolver(r.permissions.resolver), e.build();
2139
+ }
2140
+ function ye(r, e, t) {
2141
+ const s = A.builder().server(r).catalog(e.catalog).moduleLoaders(e.moduleLoaders ?? {}).context(e.context).startup({ mode: "STATIC", toolsets: [] }).registerMetaTools(!1);
2142
+ return t && s.exposurePolicy(t), s.build();
2143
+ }
2144
+ function Ue(r, e) {
2145
+ return (t) => {
2146
+ const s = r.createServer(), o = ye(s, r, e);
2147
+ return { server: s, orchestrator: o };
2148
+ };
1882
2149
  }
1883
- function qe(o) {
1884
- return o;
2150
+ function Je(r, e, t) {
2151
+ const s = $.builder().defaultManager(e).createPermissionAwareBundle(t).host(r.http?.host ?? "0.0.0.0").port(r.http?.port ?? 3e3).basePath(r.http?.basePath ?? "/").cors(r.http?.cors ?? !0).logger(r.http?.logger ?? !1);
2152
+ return r.http?.app && s.app(r.http.app), r.http?.customEndpoints && s.customEndpoints(r.http.customEndpoints), r.configSchema && s.configSchema(r.configSchema), s.build();
1885
2153
  }
1886
2154
  export {
1887
- fe as SessionContextResolver,
1888
- De as createMcpServer,
1889
- ze as createPermissionBasedMcpServer,
1890
- _e as defineEndpoint,
1891
- qe as definePermissionAwareEndpoint
2155
+ k as SessionContextResolver,
2156
+ nt as createMcpServer,
2157
+ it as createPermissionBasedMcpServer,
2158
+ rt as defineEndpoint,
2159
+ ot as definePermissionAwareEndpoint
1892
2160
  };
1893
2161
  //# sourceMappingURL=index.js.map