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