toolception 0.6.1 → 0.6.2

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 +49 -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 +1087 -850
  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 +1 -1
  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 ge = 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 ye = (r, e, t) => e in r ? ge(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t;
6
+ var d = (r, e, t) => ye(r, typeof e != "symbol" ? e + "" : e, t), ve = (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) => (ve(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 be } 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
29
  };
30
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
+ }
39
+ };
40
+ return t;
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 T = "_meta";
524
+ function Te(r, e, t, s) {
525
+ (s?.mode ?? "DYNAMIC") === "DYNAMIC" && (t.addForToolset(T, "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(T, "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(T, "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(T, "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(T, "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 && Te(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 w, M;
750
+ const D = class D {
631
751
  constructor(e = {}) {
632
- A(this, x);
752
+ x(this, w);
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, w, 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, w, 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
+ w = 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 tt(r) {
849
+ return r;
850
+ }
851
+ function st(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 we = 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,106 @@ 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 = we.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
+ const v = S();
1092
+ f = new Q({
1093
+ sessionIdGenerator: () => v,
1094
+ onsessioninitialized: (b) => {
1095
+ c.sessions.set(b, f);
874
1096
  }
875
1097
  });
876
1098
  try {
877
- await u.server.connect(g);
1099
+ await c.server.connect(f);
878
1100
  } catch {
879
- return r.code(500), {
1101
+ return o.code(500), {
880
1102
  jsonrpc: "2.0",
881
1103
  error: { code: -32603, message: "Error initializing server." },
882
1104
  id: null
883
1105
  };
884
1106
  }
885
- g.onclose = () => {
886
- g?.sessionId && u.sessions.delete(g.sessionId);
1107
+ f.onclose = () => {
1108
+ f?.sessionId && c.sessions.delete(f.sessionId);
887
1109
  };
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(
1116
+ return await f.handleRequest(
895
1117
  s.raw,
896
- r.raw,
1118
+ o.raw,
897
1119
  s.body
898
- ), r;
1120
+ ), o;
899
1121
  }
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);
1122
+ );
1123
+ }
1124
+ /**
1125
+ * @param app - Fastify instance
1126
+ * @param base - Base path for routes
1127
+ */
1128
+ registerMcpGetEndpoint(e, t) {
1129
+ e.get(`${t}/mcp`, async (s, o) => {
1130
+ const n = s.headers["mcp-client-id"]?.trim(), i = n && n.length > 0 ? n : "";
1131
+ if (!i)
1132
+ return o.code(400), "Missing mcp-client-id";
1133
+ const { cacheKey: a } = this.resolveSessionContext(s, i), l = this.clientCache.get(a);
905
1134
  if (!l)
906
- return r.code(400), "Invalid or expired client";
1135
+ return o.code(400), "Invalid or expired client";
907
1136
  const c = s.headers["mcp-session-id"];
908
1137
  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(
1138
+ return o.code(400), "Missing mcp-session-id";
1139
+ const u = l.sessions.get(c);
1140
+ return u ? (await u.handleRequest(s.raw, o.raw), o) : (o.code(400), "Invalid or expired session ID");
1141
+ });
1142
+ }
1143
+ /**
1144
+ * @param app - Fastify instance
1145
+ * @param base - Base path for routes
1146
+ */
1147
+ registerMcpDeleteEndpoint(e, t) {
1148
+ e.delete(
913
1149
  `${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), {
1150
+ async (s, o) => {
1151
+ const n = s.headers["mcp-client-id"]?.trim(), i = n && n.length > 0 ? n : "", a = s.headers["mcp-session-id"];
1152
+ if (!i || !a)
1153
+ return o.code(400), {
918
1154
  jsonrpc: "2.0",
919
1155
  error: {
920
1156
  code: -32600,
@@ -922,59 +1158,47 @@ class he {
922
1158
  },
923
1159
  id: null
924
1160
  };
925
- const c = this.clientCache.get(n), a = c?.sessions.get(l);
926
- if (!c || !a)
927
- return r.code(404), {
1161
+ const { cacheKey: l } = this.resolveSessionContext(s, i), c = this.clientCache.get(l), u = c?.sessions.get(a);
1162
+ if (!c || !u)
1163
+ return o.code(404), {
928
1164
  jsonrpc: "2.0",
929
1165
  error: { code: -32e3, message: "Session not found or expired" },
930
1166
  id: null
931
1167
  };
932
1168
  try {
933
- if (typeof a.close == "function")
1169
+ if (typeof u.close == "function")
934
1170
  try {
935
- await a.close();
1171
+ await u.close();
936
1172
  } catch {
937
1173
  }
938
1174
  } finally {
939
- a?.sessionId ? c.sessions.delete(a.sessionId) : c.sessions.delete(l);
1175
+ u?.sessionId ? c.sessions.delete(u.sessionId) : c.sessions.delete(a);
940
1176
  }
941
- return r.code(204).send(), r;
1177
+ return o.code(204).send(), o;
942
1178
  }
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;
1179
+ );
944
1180
  }
945
- /**
946
- * Stops the Fastify server and cleans up all resources.
947
- * Closes all client sessions and clears the cache.
948
- */
949
1181
  async stop() {
950
1182
  this.app && (this.clientCache.stop(!0), this.options.app || await this.app.close(), this.app = null);
951
1183
  }
952
1184
  /**
953
- * Cleans up resources associated with a client bundle.
954
- * Closes all sessions within the bundle.
955
1185
  * @param bundle - The client bundle to clean up
956
- * @private
957
1186
  */
958
1187
  cleanupBundle(e) {
959
1188
  for (const [t, s] of e.sessions.entries())
960
1189
  try {
961
- typeof s.close == "function" && s.close().catch((r) => {
962
- console.warn(`Error closing session ${t}:`, r);
1190
+ typeof s.close == "function" && s.close().catch((o) => {
1191
+ console.warn(`Error closing session ${t}:`, o);
963
1192
  });
964
- } catch (r) {
965
- console.warn(`Error closing session ${t}:`, r);
1193
+ } catch (o) {
1194
+ console.warn(`Error closing session ${t}:`, o);
966
1195
  }
967
1196
  e.sessions.clear();
968
1197
  }
969
1198
  /**
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
1199
  * @param req - The Fastify request
975
1200
  * @param clientId - The client identifier
976
1201
  * @returns Object with cache key and merged context
977
- * @private
978
1202
  */
979
1203
  resolveSessionContext(e, t) {
980
1204
  if (!this.sessionContextResolver)
@@ -986,45 +1210,38 @@ class he {
986
1210
  clientId: t,
987
1211
  headers: this.extractHeaders(e),
988
1212
  query: this.extractQuery(e)
989
- }, r = this.sessionContextResolver.resolve(
1213
+ }, o = this.sessionContextResolver.resolve(
990
1214
  s,
991
1215
  this.baseContext
992
1216
  );
993
1217
  return {
994
- cacheKey: r.cacheKeySuffix === "default" ? t : `${t}:${r.cacheKeySuffix}`,
995
- mergedContext: r.context
1218
+ cacheKey: o.cacheKeySuffix === "default" ? t : `${t}:${o.cacheKeySuffix}`,
1219
+ mergedContext: o.context
996
1220
  };
997
1221
  }
998
1222
  /**
999
- * Extracts headers from a Fastify request as a Record.
1000
- * Normalizes header names to lowercase.
1001
- *
1002
1223
  * @param req - The Fastify request
1003
1224
  * @returns Headers as a string record
1004
- * @private
1005
1225
  */
1006
1226
  extractHeaders(e) {
1007
1227
  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]);
1228
+ for (const [s, o] of Object.entries(e.headers))
1229
+ typeof o == "string" ? t[s.toLowerCase()] = o : Array.isArray(o) && o.length > 0 && (t[s.toLowerCase()] = o[0]);
1010
1230
  return t;
1011
1231
  }
1012
1232
  /**
1013
- * Extracts query parameters from a Fastify request as a Record.
1014
- *
1015
1233
  * @param req - The Fastify request
1016
1234
  * @returns Query parameters as a string record
1017
- * @private
1018
1235
  */
1019
1236
  extractQuery(e) {
1020
1237
  const t = {}, s = e.query;
1021
1238
  if (s && typeof s == "object")
1022
- for (const [r, i] of Object.entries(s))
1023
- typeof i == "string" && (t[r] = i);
1239
+ for (const [o, n] of Object.entries(s))
1240
+ typeof n == "string" && (t[o] = n);
1024
1241
  return t;
1025
1242
  }
1026
1243
  }
1027
- class fe {
1244
+ class k {
1028
1245
  constructor(e) {
1029
1246
  d(this, "config");
1030
1247
  d(this, "queryParamName");
@@ -1033,9 +1250,27 @@ class fe {
1033
1250
  d(this, "mergeStrategy");
1034
1251
  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
1252
  }
1253
+ static builder() {
1254
+ const e = {}, t = {
1255
+ enabled(s) {
1256
+ return e.enabled = s, t;
1257
+ },
1258
+ queryParam(s) {
1259
+ return e.queryParam = s, t;
1260
+ },
1261
+ contextResolver(s) {
1262
+ return e.contextResolver = s, t;
1263
+ },
1264
+ merge(s) {
1265
+ return e.merge = s, t;
1266
+ },
1267
+ build() {
1268
+ return new k(e);
1269
+ }
1270
+ };
1271
+ return t;
1272
+ }
1036
1273
  /**
1037
- * Resolves the session context for a request.
1038
- *
1039
1274
  * @param request - The request context (clientId, headers, query)
1040
1275
  * @param baseContext - The base context from server configuration
1041
1276
  * @returns The resolved context and cache key suffix
@@ -1047,34 +1282,48 @@ class fe {
1047
1282
  cacheKeySuffix: "default"
1048
1283
  };
1049
1284
  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
- }
1285
+ return this.config.contextResolver ? this.resolveWithCustomResolver(e, t, s) : this.resolveWithDefaultMerge(t, s);
1286
+ }
1287
+ /**
1288
+ * @param request - The request context
1289
+ * @param baseContext - The base context from server configuration
1290
+ * @param parsedConfig - The parsed query parameter config
1291
+ * @returns The resolved context and cache key suffix
1292
+ */
1293
+ resolveWithCustomResolver(e, t, s) {
1294
+ const o = this.config.contextResolver;
1295
+ if (!o)
1296
+ return { context: t, cacheKeySuffix: "default" };
1297
+ try {
1298
+ return {
1299
+ context: o(
1300
+ e,
1301
+ t,
1302
+ s
1303
+ ),
1304
+ cacheKeySuffix: this.generateCacheKeySuffix(s)
1305
+ };
1306
+ } catch {
1307
+ return {
1308
+ context: t,
1309
+ cacheKeySuffix: "default"
1310
+ };
1311
+ }
1312
+ }
1313
+ /**
1314
+ * @param baseContext - The base context from server configuration
1315
+ * @param parsedConfig - The parsed query parameter config
1316
+ * @returns The merged context and cache key suffix
1317
+ */
1318
+ resolveWithDefaultMerge(e, t) {
1066
1319
  return {
1067
- context: this.mergeContexts(t, s),
1068
- cacheKeySuffix: this.generateCacheKeySuffix(s)
1320
+ context: this.mergeContexts(e, t),
1321
+ cacheKeySuffix: this.generateCacheKeySuffix(t)
1069
1322
  };
1070
1323
  }
1071
1324
  /**
1072
- * Parses the session config from query parameters.
1073
- * Returns empty object on parse failure (fail secure).
1074
- *
1075
1325
  * @param query - Query parameters from the request
1076
1326
  * @returns Parsed and filtered config object
1077
- * @private
1078
1327
  */
1079
1328
  parseQueryConfig(e) {
1080
1329
  const t = e[this.queryParamName];
@@ -1083,19 +1332,15 @@ class fe {
1083
1332
  try {
1084
1333
  let s;
1085
1334
  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);
1335
+ const o = JSON.parse(s);
1336
+ return typeof o != "object" || o === null || Array.isArray(o) ? {} : this.filterAllowedKeys(o);
1088
1337
  } catch {
1089
1338
  return {};
1090
1339
  }
1091
1340
  }
1092
1341
  /**
1093
- * Filters the parsed config to only include allowed keys.
1094
- * If no allowedKeys whitelist is configured, returns the full object.
1095
- *
1096
1342
  * @param parsed - The parsed config object
1097
1343
  * @returns Filtered config with only allowed keys
1098
- * @private
1099
1344
  */
1100
1345
  filterAllowedKeys(e) {
1101
1346
  if (!this.allowedKeys)
@@ -1106,12 +1351,9 @@ class fe {
1106
1351
  return t;
1107
1352
  }
1108
1353
  /**
1109
- * Merges the base context with the session config.
1110
- *
1111
1354
  * @param baseContext - The base context from server configuration
1112
1355
  * @param sessionConfig - The parsed session config
1113
1356
  * @returns Merged context
1114
- * @private
1115
1357
  */
1116
1358
  mergeContexts(e, t) {
1117
1359
  return Object.keys(t).length === 0 ? e : typeof e != "object" || e === null || Array.isArray(e) ? t : this.mergeStrategy === "deep" ? this.deepMerge(
@@ -1123,73 +1365,65 @@ class fe {
1123
1365
  };
1124
1366
  }
1125
1367
  /**
1126
- * Performs a deep merge of two objects.
1127
- * Session config values override base context values.
1128
- *
1129
1368
  * @param base - The base object
1130
1369
  * @param override - The override object
1131
1370
  * @returns Deep merged object
1132
- * @private
1133
1371
  */
1134
1372
  deepMerge(e, t) {
1135
1373
  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;
1374
+ for (const [o, n] of Object.entries(t)) {
1375
+ const i = s[o];
1376
+ typeof n == "object" && n !== null && !Array.isArray(n) && typeof i == "object" && i !== null && !Array.isArray(i) ? s[o] = this.deepMerge(
1377
+ i,
1378
+ n
1379
+ ) : s[o] = n;
1142
1380
  }
1143
1381
  return s;
1144
1382
  }
1145
1383
  /**
1146
- * Generates a deterministic cache key suffix based on the session config.
1147
- * Returns 'default' when no session config is present.
1148
- *
1149
1384
  * @param sessionConfig - The parsed session config
1150
1385
  * @returns Hash string or 'default'
1151
- * @private
1152
1386
  */
1153
1387
  generateCacheKeySuffix(e) {
1154
1388
  if (Object.keys(e).length === 0)
1155
1389
  return "default";
1156
1390
  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);
1391
+ for (const n of t)
1392
+ s[n] = e[n];
1393
+ const o = JSON.stringify(s);
1394
+ return be("sha256").update(o).digest("hex").slice(0, 16);
1161
1395
  }
1162
1396
  }
1163
- function K(o) {
1164
- me(o), ye(o), ge(o), pe(o), ve(o);
1397
+ function X(r) {
1398
+ xe(r), Se(r), Ee(r), Ce(r), Ae(r);
1165
1399
  }
1166
- function me(o) {
1167
- if (!o || typeof o != "object")
1400
+ function xe(r) {
1401
+ if (!r || typeof r != "object")
1168
1402
  throw new Error(
1169
1403
  "Session context configuration must be an object"
1170
1404
  );
1171
1405
  }
1172
- function ye(o) {
1173
- if (o.enabled !== void 0 && typeof o.enabled != "boolean")
1406
+ function Se(r) {
1407
+ if (r.enabled !== void 0 && typeof r.enabled != "boolean")
1174
1408
  throw new Error(
1175
- `enabled must be a boolean, got ${typeof o.enabled}`
1409
+ `enabled must be a boolean, got ${typeof r.enabled}`
1176
1410
  );
1177
1411
  }
1178
- function ge(o) {
1179
- if (o.queryParam !== void 0) {
1180
- if (typeof o.queryParam != "object" || o.queryParam === null)
1412
+ function Ee(r) {
1413
+ if (r.queryParam !== void 0) {
1414
+ if (typeof r.queryParam != "object" || r.queryParam === null)
1181
1415
  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))
1416
+ if (r.queryParam.name !== void 0 && (typeof r.queryParam.name != "string" || r.queryParam.name.length === 0))
1183
1417
  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")
1418
+ if (r.queryParam.encoding !== void 0 && r.queryParam.encoding !== "base64" && r.queryParam.encoding !== "json")
1185
1419
  throw new Error(
1186
- `Invalid queryParam.encoding: "${o.queryParam.encoding}". Must be "base64" or "json"`
1420
+ `Invalid queryParam.encoding: "${r.queryParam.encoding}". Must be "base64" or "json"`
1187
1421
  );
1188
- if (o.queryParam.allowedKeys !== void 0) {
1189
- if (!Array.isArray(o.queryParam.allowedKeys))
1422
+ if (r.queryParam.allowedKeys !== void 0) {
1423
+ if (!Array.isArray(r.queryParam.allowedKeys))
1190
1424
  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];
1425
+ for (let e = 0; e < r.queryParam.allowedKeys.length; e++) {
1426
+ const t = r.queryParam.allowedKeys[e];
1193
1427
  if (typeof t != "string" || t.length === 0)
1194
1428
  throw new Error(
1195
1429
  `queryParam.allowedKeys[${e}] must be a non-empty string`
@@ -1198,172 +1432,244 @@ function ge(o) {
1198
1432
  }
1199
1433
  }
1200
1434
  }
1201
- function pe(o) {
1202
- if (o.contextResolver !== void 0 && typeof o.contextResolver != "function")
1435
+ function Ce(r) {
1436
+ if (r.contextResolver !== void 0 && typeof r.contextResolver != "function")
1203
1437
  throw new Error(
1204
1438
  "contextResolver must be a function: (request, baseContext, parsedQueryConfig?) => unknown"
1205
1439
  );
1206
1440
  }
1207
- function ve(o) {
1208
- if (o.merge !== void 0 && o.merge !== "shallow" && o.merge !== "deep")
1441
+ function Ae(r) {
1442
+ if (r.merge !== void 0 && r.merge !== "shallow" && r.merge !== "deep")
1209
1443
  throw new Error(
1210
- `Invalid merge strategy: "${o.merge}". Must be "shallow" or "deep"`
1444
+ `Invalid merge strategy: "${r.merge}". Must be "shallow" or "deep"`
1211
1445
  );
1212
1446
  }
1213
- const we = v.object({
1214
- mode: v.enum(["DYNAMIC", "STATIC"]).optional(),
1215
- toolsets: v.union([v.array(v.string()), v.literal("ALL")]).optional()
1447
+ const Pe = g.object({
1448
+ mode: g.enum(["DYNAMIC", "STATIC"]).optional(),
1449
+ toolsets: g.union([g.array(g.string()), g.literal("ALL")]).optional()
1216
1450
  }).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)}
1451
+ function Me(r) {
1452
+ try {
1453
+ Pe.parse(r);
1454
+ } catch (e) {
1455
+ if (e instanceof g.ZodError) {
1456
+ const t = e.format();
1457
+ throw new Error(
1458
+ `Invalid startup configuration:
1459
+ ${JSON.stringify(t, null, 2)}
1227
1460
 
1228
1461
  Hint: Common mistake - use "toolsets" not "initialToolsets"`
1229
- );
1230
- }
1231
- throw a;
1462
+ );
1232
1463
  }
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) => {
1464
+ throw e;
1465
+ }
1466
+ }
1467
+ function Ie() {
1468
+ const r = (t) => typeof t?.server?.notification == "function", e = (t) => typeof t?.notifyToolsListChanged == "function";
1469
+ return async (t) => {
1240
1470
  try {
1241
- if (r(a)) {
1242
- await a.server.notification({
1471
+ if (r(t)) {
1472
+ await t.server.notification({
1243
1473
  method: "notifications/tools/list_changed"
1244
1474
  });
1245
1475
  return;
1246
1476
  }
1247
- i(a) && await a.notifyToolsListChanged();
1248
- } catch (u) {
1249
- if ((u instanceof Error ? u.message : String(u)) === "Not connected")
1477
+ e(t) && await t.notifyToolsListChanged();
1478
+ } catch (s) {
1479
+ if ((s instanceof Error ? s.message : String(s)) === "Not connected")
1250
1480
  return;
1251
- console.warn("Failed to send tools list changed notification:", u);
1481
+ console.warn("Failed to send tools list changed notification:", s);
1252
1482
  }
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,
1483
+ };
1484
+ }
1485
+ function $e(r, e) {
1486
+ return r !== void 0 ? r : e === "DYNAMIC";
1487
+ }
1488
+ async function rt(r) {
1489
+ Re(r);
1490
+ const e = r.startup?.mode ?? "DYNAMIC", t = $e(r.registerMetaTools, e), s = Le(r, e), o = Ie(), n = r.createServer(), i = ee(
1491
+ n,
1492
+ r,
1493
+ e,
1284
1494
  t,
1285
- o.context
1495
+ o
1496
+ );
1497
+ e === "STATIC" && await i.ensureReady();
1498
+ const a = je(
1499
+ r,
1500
+ e,
1501
+ n,
1502
+ i,
1503
+ t,
1504
+ o
1505
+ ), l = Ne(
1506
+ r,
1507
+ i.getManager(),
1508
+ a,
1509
+ s
1286
1510
  );
1287
1511
  return {
1288
- server: s,
1289
- start: async () => {
1290
- await c.start();
1291
- },
1292
- close: async () => {
1293
- await c.stop();
1294
- }
1512
+ server: n,
1513
+ start: () => l.start(),
1514
+ close: () => l.stop()
1515
+ };
1516
+ }
1517
+ function Re(r) {
1518
+ if (r.startup && Me(r.startup), typeof r.createServer != "function")
1519
+ throw new Error("createMcpServer: `createServer` (factory) is required");
1520
+ }
1521
+ function Le(r, e) {
1522
+ if (!r.sessionContext) return;
1523
+ X(r.sessionContext);
1524
+ const t = k.builder().enabled(r.sessionContext.enabled ?? !0).queryParam(r.sessionContext.queryParam).contextResolver(r.sessionContext.contextResolver).merge(r.sessionContext.merge ?? "shallow").build();
1525
+ return e === "STATIC" && r.sessionContext.enabled !== !1 && console.warn(
1526
+ "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."
1527
+ ), t;
1528
+ }
1529
+ function ee(r, e, t, s, o, n) {
1530
+ 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);
1531
+ return e.exposurePolicy && i.exposurePolicy(e.exposurePolicy), e.startup && i.startup(e.startup), i.build();
1532
+ }
1533
+ function je(r, e, t, s, o, n) {
1534
+ return (i) => {
1535
+ if (e === "STATIC")
1536
+ return { server: t, orchestrator: s };
1537
+ const a = i ?? r.context, l = r.createServer(), c = ee(
1538
+ l,
1539
+ r,
1540
+ e,
1541
+ o,
1542
+ n,
1543
+ a
1544
+ );
1545
+ return { server: l, orchestrator: c };
1295
1546
  };
1296
1547
  }
1297
- function Te(o) {
1298
- be(o), Se(o), xe(o), Ae(o);
1548
+ function Ne(r, e, t, s) {
1549
+ 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);
1550
+ 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();
1551
+ }
1552
+ function Oe(r) {
1553
+ ke(r), De(r), ze(r), qe(r);
1299
1554
  }
1300
- function be(o) {
1301
- if (!o || typeof o != "object")
1555
+ function ke(r) {
1556
+ if (!r || typeof r != "object")
1302
1557
  throw new Error(
1303
1558
  "Permission configuration is required for createPermissionBasedMcpServer"
1304
1559
  );
1305
1560
  }
1306
- function Se(o) {
1307
- if (!o.source)
1561
+ function De(r) {
1562
+ if (!r.source)
1308
1563
  throw new Error('Permission source must be either "headers" or "config"');
1309
- if (o.source !== "headers" && o.source !== "config")
1564
+ if (r.source !== "headers" && r.source !== "config")
1310
1565
  throw new Error(
1311
- `Invalid permission source: "${o.source}". Must be either "headers" or "config"`
1566
+ `Invalid permission source: "${r.source}". Must be either "headers" or "config"`
1312
1567
  );
1313
1568
  }
1314
- function xe(o) {
1315
- if (o.source === "config" && !o.staticMap && !o.resolver)
1569
+ function ze(r) {
1570
+ if (r.source === "config" && !r.staticMap && !r.resolver)
1316
1571
  throw new Error(
1317
1572
  "Config-based permissions require at least one of: staticMap or resolver function"
1318
1573
  );
1319
1574
  }
1320
- function Ae(o) {
1321
- if (o.staticMap !== void 0) {
1322
- if (typeof o.staticMap != "object" || o.staticMap === null)
1575
+ function qe(r) {
1576
+ if (r.staticMap !== void 0) {
1577
+ if (typeof r.staticMap != "object" || r.staticMap === null)
1323
1578
  throw new Error(
1324
1579
  "staticMap must be an object mapping client IDs to toolset arrays"
1325
1580
  );
1326
- Ce(o.staticMap);
1581
+ Fe(r.staticMap);
1327
1582
  }
1328
- if (o.resolver !== void 0 && typeof o.resolver != "function")
1583
+ if (r.resolver !== void 0 && typeof r.resolver != "function")
1329
1584
  throw new Error(
1330
1585
  "resolver must be a synchronous function: (clientId: string) => string[]"
1331
1586
  );
1332
- if (o.defaultPermissions !== void 0 && !Array.isArray(o.defaultPermissions))
1587
+ if (r.defaultPermissions !== void 0 && !Array.isArray(r.defaultPermissions))
1333
1588
  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))
1589
+ if (r.headerName !== void 0 && (typeof r.headerName != "string" || r.headerName.length === 0))
1335
1590
  throw new Error("headerName must be a non-empty string");
1336
1591
  }
1337
- function Ce(o) {
1338
- for (const [e, t] of Object.entries(o))
1592
+ function Fe(r) {
1593
+ for (const [e, t] of Object.entries(r))
1339
1594
  if (!Array.isArray(t))
1340
1595
  throw new Error(
1341
1596
  `staticMap value for client "${e}" must be an array of toolset names`
1342
1597
  );
1343
1598
  }
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
- */
1599
+ function _e(r, e) {
1600
+ return async (t) => {
1601
+ const s = e.resolvePermissions(
1602
+ t.clientId,
1603
+ t.headers
1604
+ ), o = r(s), n = o.orchestrator.getManager(), i = [], a = [];
1605
+ if (s.length > 0) {
1606
+ const l = await n.enableToolsets(s);
1607
+ for (const c of l.results)
1608
+ c.success ? i.push(c.name) : (a.push(c.name), console.warn(
1609
+ `Failed to enable toolset '${c.name}' for client '${t.clientId}': ${c.message}`
1610
+ ));
1611
+ if (i.length === 0 && a.length > 0)
1612
+ throw new Error(
1613
+ `All requested toolsets failed to enable for client '${t.clientId}'. Requested: [${s.join(", ")}]. Check that toolset names in permissions match the catalog.`
1614
+ );
1615
+ }
1616
+ return {
1617
+ server: o.server,
1618
+ orchestrator: o.orchestrator,
1619
+ allowedToolsets: i,
1620
+ failedToolsets: a
1621
+ };
1622
+ };
1623
+ }
1624
+ function Ke(r) {
1625
+ if (!r) return;
1626
+ const e = {
1627
+ namespaceToolsWithSetKey: r.namespaceToolsWithSetKey
1628
+ };
1629
+ return r.allowlist !== void 0 && console.warn(
1630
+ "Permission-based servers: exposurePolicy.allowlist is ignored. Allowed toolsets are determined by client permissions."
1631
+ ), r.denylist !== void 0 && console.warn(
1632
+ "Permission-based servers: exposurePolicy.denylist is ignored. Use permission configuration to control toolset access."
1633
+ ), r.maxActiveToolsets !== void 0 && console.warn(
1634
+ "Permission-based servers: exposurePolicy.maxActiveToolsets is ignored. Toolset count is determined by client permissions."
1635
+ ), r.onLimitExceeded !== void 0 && console.warn(
1636
+ "Permission-based servers: exposurePolicy.onLimitExceeded is ignored. No toolset limits are enforced."
1637
+ ), e;
1638
+ }
1639
+ var y, te, se, re, oe, ne;
1640
+ const z = class z {
1350
1641
  constructor(e) {
1351
- A(this, p);
1642
+ x(this, y);
1352
1643
  d(this, "cache", /* @__PURE__ */ new Map());
1353
1644
  d(this, "normalizedHeaderName");
1354
1645
  this.config = e, this.normalizedHeaderName = (e.headerName || "mcp-toolset-permissions").toLowerCase();
1355
1646
  }
1647
+ static builder() {
1648
+ const e = {}, t = {
1649
+ source(s) {
1650
+ return e.source = s, t;
1651
+ },
1652
+ headerName(s) {
1653
+ return e.headerName = s, t;
1654
+ },
1655
+ staticMap(s) {
1656
+ return e.staticMap = s, t;
1657
+ },
1658
+ resolver(s) {
1659
+ return e.resolver = s, t;
1660
+ },
1661
+ defaultPermissions(s) {
1662
+ return e.defaultPermissions = s, t;
1663
+ },
1664
+ build() {
1665
+ return new z(e);
1666
+ }
1667
+ };
1668
+ return t;
1669
+ }
1356
1670
  /**
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
1671
  * @param clientId - The unique identifier for the client
1366
- * @param headers - Optional request headers (required for header-based permissions)
1672
+ * @param headers - Optional request headers
1367
1673
  * @returns Array of toolset names the client is allowed to access
1368
1674
  */
1369
1675
  resolvePermissions(e, t) {
@@ -1371,48 +1677,37 @@ class Ee {
1371
1677
  return this.cache.get(e);
1372
1678
  let s;
1373
1679
  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(
1680
+ 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
1681
  `Permission resolution returned non-array for client ${e}, using empty permissions`
1376
1682
  ), s = []), s = s.filter(
1377
- (r) => typeof r == "string" && r.trim().length > 0
1683
+ (o) => typeof o == "string" && o.trim().length > 0
1378
1684
  );
1379
- } catch (r) {
1685
+ } catch (o) {
1380
1686
  console.error(
1381
1687
  `Unexpected error resolving permissions for client ${e}:`,
1382
- r
1688
+ o
1383
1689
  ), s = [];
1384
1690
  }
1385
1691
  return this.cache.set(e, s), s;
1386
1692
  }
1387
1693
  /**
1388
- * Invalidates cached permissions for a specific client.
1389
- * Call this when you know a client's permissions have changed.
1390
1694
  * @param clientId - The client ID to invalidate
1391
1695
  */
1392
1696
  invalidateCache(e) {
1393
1697
  this.cache.delete(e);
1394
1698
  }
1395
- /**
1396
- * Clears the permission cache.
1397
- * Useful for cleanup during server shutdown or when permissions need to be refreshed.
1398
- */
1399
1699
  clearCache() {
1400
1700
  this.cache.clear();
1401
1701
  }
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.
1702
+ };
1703
+ y = new WeakSet(), /**
1408
1704
  * @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
1705
+ * @returns Array of toolset names from headers
1411
1706
  */
1412
- H = function(e) {
1707
+ te = function(e) {
1413
1708
  if (!e)
1414
1709
  return [];
1415
- const t = m(this, p, B).call(this, e, this.normalizedHeaderName);
1710
+ const t = m(this, y, se).call(this, e, this.normalizedHeaderName);
1416
1711
  if (!t)
1417
1712
  return [];
1418
1713
  try {
@@ -1424,47 +1719,37 @@ H = function(e) {
1424
1719
  ), [];
1425
1720
  }
1426
1721
  }, /**
1427
- * Finds a header value using case-insensitive key matching.
1428
- * HTTP headers are case-insensitive per RFC 7230.
1429
1722
  * @param headers - The headers object to search
1430
1723
  * @param normalizedKey - The lowercase key to search for
1431
- * @returns The header value if found, undefined otherwise
1432
- * @private
1724
+ * @returns The header value if found
1433
1725
  */
1434
- B = function(e, t) {
1726
+ se = function(e, t) {
1435
1727
  if (e[t] !== void 0)
1436
1728
  return e[t];
1437
- for (const [s, r] of Object.entries(e))
1729
+ for (const [s, o] of Object.entries(e))
1438
1730
  if (s.toLowerCase() === t)
1439
- return r;
1731
+ return o;
1440
1732
  }, /**
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
1733
  * @param clientId - The unique identifier for the client
1445
1734
  * @returns Array of toolset names from configuration
1446
- * @private
1447
1735
  */
1448
- Y = function(e) {
1736
+ re = function(e) {
1449
1737
  if (this.config.resolver) {
1450
- const t = m(this, p, U).call(this, e);
1738
+ const t = m(this, y, oe).call(this, e);
1451
1739
  if (t !== null)
1452
1740
  return t;
1453
1741
  }
1454
1742
  if (this.config.staticMap) {
1455
- const t = m(this, p, W).call(this, e);
1743
+ const t = m(this, y, ne).call(this, e);
1456
1744
  if (t !== null)
1457
1745
  return t;
1458
1746
  }
1459
1747
  return this.config.defaultPermissions || [];
1460
1748
  }, /**
1461
- * Attempts to resolve permissions using the configured resolver function.
1462
- * Handles errors gracefully and returns null on failure to allow fallback.
1463
1749
  * @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
1750
+ * @returns Array of toolset names if successful, null if resolver fails
1466
1751
  */
1467
- U = function(e) {
1752
+ oe = function(e) {
1468
1753
  try {
1469
1754
  const t = this.config.resolver(e);
1470
1755
  return Array.isArray(t) ? t : (console.warn(
@@ -1477,61 +1762,28 @@ U = function(e) {
1477
1762
  ), null;
1478
1763
  }
1479
1764
  }, /**
1480
- * Looks up permissions in the static map configuration.
1481
- * Returns null if client is not found to allow fallback to defaults.
1482
1765
  * @param clientId - The unique identifier for the client
1483
1766
  * @returns Array of toolset names if found, null if client not in map
1484
- * @private
1485
1767
  */
1486
- W = function(e) {
1768
+ ne = function(e) {
1487
1769
  const t = this.config.staticMap[e];
1488
1770
  return t !== void 0 ? Array.isArray(t) ? t : [] : null;
1489
1771
  };
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);
1772
+ let I = z;
1773
+ const Be = g.string({ message: "Missing required mcp-client-id header" }).trim().min(1, "mcp-client-id header must not be empty");
1774
+ var h, ie, ae, le, ce, de, ue, he, fe, R, me;
1775
+ const q = class q {
1776
+ constructor(e, t, s = {}, o) {
1777
+ x(this, h);
1526
1778
  d(this, "options");
1527
1779
  d(this, "defaultManager");
1528
1780
  d(this, "createPermissionAwareBundle");
1529
1781
  d(this, "app", null);
1530
1782
  d(this, "configSchema");
1531
1783
  // Per-client server bundles and per-client session transports
1532
- d(this, "clientCache", new F({
1784
+ d(this, "clientCache", new E({
1533
1785
  onEvict: (e, t) => {
1534
- m(this, f, J).call(this, t);
1786
+ m(this, h, ie).call(this, t);
1535
1787
  }
1536
1788
  }));
1537
1789
  this.defaultManager = e, this.createPermissionAwareBundle = t, this.options = {
@@ -1542,29 +1794,66 @@ class Me {
1542
1794
  logger: s.logger ?? !1,
1543
1795
  app: s.app,
1544
1796
  customEndpoints: s.customEndpoints
1545
- }, this.configSchema = r;
1797
+ }, this.configSchema = o;
1798
+ }
1799
+ static builder() {
1800
+ let e, t;
1801
+ const s = {};
1802
+ let o;
1803
+ const n = {
1804
+ defaultManager(i) {
1805
+ return e = i, n;
1806
+ },
1807
+ createPermissionAwareBundle(i) {
1808
+ return t = i, n;
1809
+ },
1810
+ host(i) {
1811
+ return s.host = i, n;
1812
+ },
1813
+ port(i) {
1814
+ return s.port = i, n;
1815
+ },
1816
+ basePath(i) {
1817
+ return s.basePath = i, n;
1818
+ },
1819
+ cors(i) {
1820
+ return s.cors = i, n;
1821
+ },
1822
+ logger(i) {
1823
+ return s.logger = i, n;
1824
+ },
1825
+ app(i) {
1826
+ return s.app = i, n;
1827
+ },
1828
+ customEndpoints(i) {
1829
+ return s.customEndpoints = i, n;
1830
+ },
1831
+ configSchema(i) {
1832
+ return o = i, n;
1833
+ },
1834
+ build() {
1835
+ return new q(e, t, s, o);
1836
+ }
1837
+ };
1838
+ return n;
1546
1839
  }
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
1840
  async start() {
1552
1841
  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, {
1842
+ const e = this.options.app ?? U({ logger: this.options.logger });
1843
+ this.options.cors && await e.register(J, { origin: !0 });
1844
+ const t = m(this, h, ae).call(this, this.options.basePath);
1845
+ m(this, h, le).call(this, e, t), m(this, h, ce).call(this, e, t), 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), this.options.customEndpoints && this.options.customEndpoints.length > 0 && Z(e, t, this.options.customEndpoints, {
1557
1846
  contextExtractor: async (s) => {
1558
- const r = m(this, f, M).call(this, s);
1847
+ const o = m(this, h, R).call(this, s);
1559
1848
  try {
1560
- const i = await this.createPermissionAwareBundle(r);
1849
+ const n = await this.createPermissionAwareBundle(o);
1561
1850
  return {
1562
- allowedToolsets: i.allowedToolsets,
1563
- failedToolsets: i.failedToolsets
1851
+ allowedToolsets: n.allowedToolsets,
1852
+ failedToolsets: n.failedToolsets
1564
1853
  };
1565
- } catch (i) {
1854
+ } catch (n) {
1566
1855
  return console.warn(
1567
- `Permission resolution failed for custom endpoint: ${i}`
1856
+ `Permission resolution failed for custom endpoint: ${n}`
1568
1857
  ), {
1569
1858
  allowedToolsets: [],
1570
1859
  failedToolsets: []
@@ -1573,62 +1862,47 @@ class Me {
1573
1862
  }
1574
1863
  }), this.options.app || await e.listen({ host: this.options.host, port: this.options.port }), this.app = e;
1575
1864
  }
1576
- /**
1577
- * Stops the Fastify server and cleans up all resources.
1578
- * Closes all client sessions and clears the cache.
1579
- */
1580
1865
  async stop() {
1581
1866
  this.app && (this.clientCache.stop(!0), this.options.app || await this.app.close(), this.app = null);
1582
1867
  }
1583
- }
1584
- f = new WeakSet(), /**
1585
- * Cleans up resources associated with a client bundle.
1586
- * Closes all sessions within the bundle.
1868
+ };
1869
+ h = new WeakSet(), /**
1587
1870
  * @param bundle - The client bundle to clean up
1588
- * @private
1589
1871
  */
1590
- J = function(e) {
1872
+ ie = function(e) {
1591
1873
  for (const [t, s] of e.sessions.entries())
1592
1874
  try {
1593
- typeof s.close == "function" && s.close().catch((r) => {
1594
- console.warn(`Error closing session ${t}:`, r);
1875
+ typeof s.close == "function" && s.close().catch((o) => {
1876
+ console.warn(`Error closing session ${t}:`, o);
1595
1877
  });
1596
- } catch (r) {
1597
- console.warn(`Error closing session ${t}:`, r);
1878
+ } catch (o) {
1879
+ console.warn(`Error closing session ${t}:`, o);
1598
1880
  }
1599
1881
  e.sessions.clear();
1600
1882
  }, /**
1601
- * Normalizes the base path by removing trailing slashes.
1602
1883
  * @param basePath - The base path to normalize
1603
1884
  * @returns Normalized base path without trailing slash
1604
- * @private
1605
1885
  */
1606
- Q = function(e) {
1886
+ ae = function(e) {
1607
1887
  return e.endsWith("/") ? e.slice(0, -1) : e;
1608
1888
  }, /**
1609
- * Registers the health check endpoint.
1610
1889
  * @param app - Fastify instance
1611
1890
  * @param base - Base path for routes
1612
- * @private
1613
1891
  */
1614
- G = function(e, t) {
1892
+ le = function(e, t) {
1615
1893
  e.get(`${t}/healthz`, async () => ({ ok: !0 }));
1616
1894
  }, /**
1617
- * Registers the tools status endpoint.
1618
1895
  * @param app - Fastify instance
1619
1896
  * @param base - Base path for routes
1620
- * @private
1621
1897
  */
1622
- Z = function(e, t) {
1898
+ ce = function(e, t) {
1623
1899
  e.get(`${t}/tools`, async () => this.defaultManager.getStatus());
1624
1900
  }, /**
1625
- * Registers the MCP configuration discovery endpoint.
1626
1901
  * @param app - Fastify instance
1627
1902
  * @param base - Base path for routes
1628
- * @private
1629
1903
  */
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 ?? {
1904
+ de = function(e, t) {
1905
+ e.get(`${t}/.well-known/mcp-config`, async (s, o) => (o.header("Content-Type", "application/schema+json; charset=utf-8"), this.configSchema ?? {
1632
1906
  $schema: "https://json-schema.org/draft/2020-12/schema",
1633
1907
  title: "MCP Session Configuration",
1634
1908
  description: "Schema for the /mcp endpoint configuration",
@@ -1639,108 +1913,110 @@ X = function(e, t) {
1639
1913
  "x-query-style": "dot+bracket"
1640
1914
  }));
1641
1915
  }, /**
1642
- * Registers the POST /mcp endpoint for JSON-RPC requests.
1643
- * Extracts client context, resolves permissions, and handles MCP protocol.
1644
1916
  * @param app - Fastify instance
1645
1917
  * @param base - Base path for routes
1646
- * @private
1647
1918
  */
1648
- ee = function(e, t) {
1919
+ ue = function(e, t) {
1649
1920
  e.post(
1650
1921
  `${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)
1922
+ async (s, o) => {
1923
+ const n = Be.safeParse(
1924
+ s.headers["mcp-client-id"]
1925
+ );
1926
+ if (!n.success)
1927
+ return o.code(400), {
1928
+ jsonrpc: "2.0",
1929
+ error: { code: -32600, message: n.error.issues[0].message },
1930
+ id: null
1931
+ };
1932
+ const i = m(this, h, R).call(this, s);
1933
+ let a = this.clientCache.get(i.clientId);
1934
+ if (!a)
1655
1935
  try {
1656
1936
  const u = await this.createPermissionAwareBundle(i);
1657
1937
  u.failedToolsets.length > 0 && console.warn(
1658
1938
  `Client ${i.clientId} had ${u.failedToolsets.length} toolsets fail to enable: [${u.failedToolsets.join(", ")}]. Successfully enabled: [${u.allowedToolsets.join(", ")}]`
1659
1939
  );
1660
- const h = u.sessions;
1661
- l = {
1940
+ const f = u.sessions;
1941
+ a = {
1662
1942
  server: u.server,
1663
1943
  orchestrator: u.orchestrator,
1664
1944
  allowedToolsets: u.allowedToolsets,
1665
1945
  failedToolsets: u.failedToolsets,
1666
- sessions: h instanceof Map ? h : /* @__PURE__ */ new Map()
1667
- }, n && this.clientCache.set(i.clientId, l);
1946
+ sessions: f instanceof Map ? f : /* @__PURE__ */ new Map()
1947
+ }, this.clientCache.set(i.clientId, a);
1668
1948
  } catch (u) {
1669
1949
  return console.error(
1670
1950
  `Failed to create permission-aware bundle for client ${i.clientId}:`,
1671
1951
  u
1672
- ), r.code(403), m(this, f, oe).call(this, "Access denied");
1952
+ ), o.code(403), m(this, h, me).call(this, "Access denied");
1673
1953
  }
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)) {
1954
+ const l = s.headers["mcp-session-id"];
1955
+ let c;
1956
+ if (l && a.sessions.get(l))
1957
+ c = a.sessions.get(l);
1958
+ else if (!l && G(s.body)) {
1679
1959
  const u = S();
1680
- a = new z({
1960
+ c = new Q({
1681
1961
  sessionIdGenerator: () => u,
1682
- onsessioninitialized: (h) => {
1683
- l.sessions.set(h, a);
1962
+ onsessioninitialized: (f) => {
1963
+ a.sessions.set(f, c);
1684
1964
  }
1685
1965
  });
1686
1966
  try {
1687
- await l.server.connect(a);
1967
+ await a.server.connect(c);
1688
1968
  } catch {
1689
- return r.code(500), {
1969
+ return o.code(500), {
1690
1970
  jsonrpc: "2.0",
1691
1971
  error: { code: -32603, message: "Error initializing server." },
1692
1972
  id: null
1693
1973
  };
1694
1974
  }
1695
- a.onclose = () => {
1696
- a?.sessionId && l.sessions.delete(a.sessionId);
1975
+ c.onclose = () => {
1976
+ c?.sessionId && a.sessions.delete(c.sessionId);
1697
1977
  };
1698
1978
  } else
1699
- return r.code(400), {
1979
+ return o.code(400), {
1700
1980
  jsonrpc: "2.0",
1701
1981
  error: { code: -32e3, message: "Session not found or expired" },
1702
1982
  id: null
1703
1983
  };
1704
- return await a.handleRequest(
1984
+ return await c.handleRequest(
1705
1985
  s.raw,
1706
- r.raw,
1986
+ o.raw,
1707
1987
  s.body
1708
- ), r;
1988
+ ), o;
1709
1989
  }
1710
1990
  );
1711
1991
  }, /**
1712
- * Registers the GET /mcp endpoint for SSE notifications.
1713
1992
  * @param app - Fastify instance
1714
1993
  * @param base - Base path for routes
1715
- * @private
1716
1994
  */
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);
1995
+ he = function(e, t) {
1996
+ e.get(`${t}/mcp`, async (s, o) => {
1997
+ const n = s.headers["mcp-client-id"]?.trim(), i = n && n.length > 0 ? n : "";
1998
+ if (!i)
1999
+ return o.code(400), "Missing mcp-client-id";
2000
+ const a = this.clientCache.get(i);
2001
+ if (!a)
2002
+ return o.code(400), "Invalid or expired client";
2003
+ const l = s.headers["mcp-session-id"];
1723
2004
  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");
2005
+ return o.code(400), "Missing mcp-session-id";
2006
+ const c = a.sessions.get(l);
2007
+ return c ? (await c.handleRequest(s.raw, o.raw), o) : (o.code(400), "Invalid or expired session ID");
1730
2008
  });
1731
2009
  }, /**
1732
- * Registers the DELETE /mcp endpoint for session termination.
1733
2010
  * @param app - Fastify instance
1734
2011
  * @param base - Base path for routes
1735
- * @private
1736
2012
  */
1737
- se = function(e, t) {
2013
+ fe = function(e, t) {
1738
2014
  e.delete(
1739
2015
  `${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), {
2016
+ async (s, o) => {
2017
+ const n = s.headers["mcp-client-id"]?.trim(), i = n && n.length > 0 ? n : "", a = s.headers["mcp-session-id"];
2018
+ if (!i || !a)
2019
+ return o.code(400), {
1744
2020
  jsonrpc: "2.0",
1745
2021
  error: {
1746
2022
  code: -32600,
@@ -1748,46 +2024,40 @@ se = function(e, t) {
1748
2024
  },
1749
2025
  id: null
1750
2026
  };
1751
- const c = this.clientCache.get(n), a = c?.sessions.get(l);
1752
- if (!c || !a)
1753
- return r.code(404), {
2027
+ const l = this.clientCache.get(i), c = l?.sessions.get(a);
2028
+ if (!l || !c)
2029
+ return o.code(404), {
1754
2030
  jsonrpc: "2.0",
1755
2031
  error: { code: -32e3, message: "Session not found or expired" },
1756
2032
  id: null
1757
2033
  };
1758
2034
  try {
1759
- if (typeof a.close == "function")
2035
+ if (typeof c.close == "function")
1760
2036
  try {
1761
- await a.close();
2037
+ await c.close();
1762
2038
  } catch {
1763
2039
  }
1764
2040
  } finally {
1765
- a?.sessionId ? c.sessions.delete(a.sessionId) : c.sessions.delete(l);
2041
+ c?.sessionId ? l.sessions.delete(c.sessionId) : l.sessions.delete(a);
1766
2042
  }
1767
- return r.code(204).send(), r;
2043
+ return o.code(204).send(), o;
1768
2044
  }
1769
2045
  );
1770
2046
  }, /**
1771
- * Extracts client context from the request.
1772
- * Generates anonymous client ID if not provided in headers.
1773
2047
  * @param req - Fastify request object
1774
2048
  * @returns Client request context with ID and headers
1775
- * @private
1776
2049
  */
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 };
2050
+ R = function(e) {
2051
+ const t = e.headers["mcp-client-id"]?.trim(), s = t && t.length > 0 ? t : `anon-${S()}`, o = {};
2052
+ for (const [n, i] of Object.entries(e.headers))
2053
+ typeof i == "string" && (o[n] = i);
2054
+ return { clientId: s, headers: o };
1782
2055
  }, /**
1783
- * Creates a safe error response that doesn't expose unauthorized toolset information.
1784
- * Used for permission-related errors to prevent information leakage.
1785
2056
  * @param message - Generic error message to return to client
1786
- * @param code - JSON-RPC error code (default: -32000 for server error)
2057
+ * @param code - JSON-RPC error code
1787
2058
  * @returns JSON-RPC error response object
1788
- * @private
1789
2059
  */
1790
- oe = function(e = "Access denied", t = -32e3) {
2060
+ me = function(e = "Access denied", t = -32e3) {
1791
2061
  return {
1792
2062
  jsonrpc: "2.0",
1793
2063
  error: {
@@ -1797,97 +2067,64 @@ oe = function(e = "Access denied", t = -32e3) {
1797
2067
  id: null
1798
2068
  };
1799
2069
  };
1800
- function Ie(o) {
1801
- if (!o) return;
1802
- const e = {
1803
- namespaceToolsWithSetKey: o.namespaceToolsWithSetKey
2070
+ let $ = q;
2071
+ async function ot(r) {
2072
+ He(r);
2073
+ const e = Ke(r.exposurePolicy), t = Ve(r), s = r.createServer(), o = pe(s, r, e), n = _e(
2074
+ We(r, e),
2075
+ t
2076
+ ), i = Ye(r, o.getManager(), n);
2077
+ return {
2078
+ server: s,
2079
+ start: () => i.start(),
2080
+ close: async () => {
2081
+ try {
2082
+ await i.stop();
2083
+ } finally {
2084
+ t.clearCache();
2085
+ }
2086
+ }
1804
2087
  };
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
2088
  }
1815
- async function ze(o) {
1816
- if (!o.permissions)
2089
+ function He(r) {
2090
+ if (!r.permissions)
1817
2091
  throw new Error(
1818
2092
  "Permission configuration is required for createPermissionBasedMcpServer. Please provide a 'permissions' field in the options."
1819
2093
  );
1820
- if (Te(o.permissions), o.sessionContext && (K(o.sessionContext), console.warn(
2094
+ if (Oe(r.permissions), r.sessionContext && (X(r.sessionContext), console.warn(
1821
2095
  "Session context support for permission-based servers is limited. The base context will be used for module loaders."
1822
- )), o.startup)
2096
+ )), r.startup)
1823
2097
  throw new Error(
1824
2098
  "Permission-based servers determine toolsets from client permissions. The 'startup' option is not allowed. Remove it from your configuration."
1825
2099
  );
1826
- if (typeof o.createServer != "function")
2100
+ if (typeof r.createServer != "function")
1827
2101
  throw new Error(
1828
2102
  "createPermissionBasedMcpServer: `createServer` (factory) is required"
1829
2103
  );
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
2104
  }
1880
- function _e(o) {
1881
- return o;
2105
+ function Ve(r) {
2106
+ const e = I.builder().source(r.permissions.source).headerName(r.permissions.headerName ?? "mcp-toolset-permissions").staticMap(r.permissions.staticMap ?? {}).defaultPermissions(r.permissions.defaultPermissions ?? []);
2107
+ return r.permissions.resolver && e.resolver(r.permissions.resolver), e.build();
2108
+ }
2109
+ function pe(r, e, t) {
2110
+ const s = A.builder().server(r).catalog(e.catalog).moduleLoaders(e.moduleLoaders ?? {}).context(e.context).startup({ mode: "STATIC", toolsets: [] }).registerMetaTools(!1);
2111
+ return t && s.exposurePolicy(t), s.build();
2112
+ }
2113
+ function We(r, e) {
2114
+ return (t) => {
2115
+ const s = r.createServer(), o = pe(s, r, e);
2116
+ return { server: s, orchestrator: o };
2117
+ };
1882
2118
  }
1883
- function qe(o) {
1884
- return o;
2119
+ function Ye(r, e, t) {
2120
+ 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);
2121
+ 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
2122
  }
1886
2123
  export {
1887
- fe as SessionContextResolver,
1888
- De as createMcpServer,
1889
- ze as createPermissionBasedMcpServer,
1890
- _e as defineEndpoint,
1891
- qe as definePermissionAwareEndpoint
2124
+ k as SessionContextResolver,
2125
+ rt as createMcpServer,
2126
+ ot as createPermissionBasedMcpServer,
2127
+ tt as defineEndpoint,
2128
+ st as definePermissionAwareEndpoint
1892
2129
  };
1893
2130
  //# sourceMappingURL=index.js.map