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.
- package/README.md +1 -1
- package/dist/core/DynamicToolManager.d.ts +33 -22
- package/dist/core/DynamicToolManager.d.ts.map +1 -1
- package/dist/core/ServerOrchestrator.d.ts +33 -25
- package/dist/core/ServerOrchestrator.d.ts.map +1 -1
- package/dist/core/ToolRegistry.d.ts +5 -3
- package/dist/core/ToolRegistry.d.ts.map +1 -1
- package/dist/core/core.types.d.ts +29 -0
- package/dist/core/core.types.d.ts.map +1 -0
- package/dist/http/FastifyTransport.d.ts +49 -41
- package/dist/http/FastifyTransport.d.ts.map +1 -1
- package/dist/http/{customEndpoints.d.ts → http.types.d.ts} +33 -86
- package/dist/http/http.types.d.ts.map +1 -0
- package/dist/http/http.utils.d.ts +121 -0
- package/dist/http/http.utils.d.ts.map +1 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1076 -829
- package/dist/index.js.map +1 -1
- package/dist/meta/registerMetaTools.d.ts +12 -1
- package/dist/meta/registerMetaTools.d.ts.map +1 -1
- package/dist/mode/ModeResolver.d.ts +11 -10
- package/dist/mode/ModeResolver.d.ts.map +1 -1
- package/dist/mode/ModuleResolver.d.ts +18 -4
- package/dist/mode/ModuleResolver.d.ts.map +1 -1
- package/dist/mode/mode.types.d.ts +15 -0
- package/dist/mode/mode.types.d.ts.map +1 -0
- package/dist/permissions/PermissionAwareFastifyTransport.d.ts +15 -39
- package/dist/permissions/PermissionAwareFastifyTransport.d.ts.map +1 -1
- package/dist/permissions/PermissionResolver.d.ts +9 -24
- package/dist/permissions/PermissionResolver.d.ts.map +1 -1
- package/dist/permissions/{createPermissionAwareBundle.d.ts → permissions.types.d.ts} +17 -18
- package/dist/permissions/permissions.types.d.ts.map +1 -0
- package/dist/permissions/permissions.utils.d.ts +31 -0
- package/dist/permissions/permissions.utils.d.ts.map +1 -0
- package/dist/server/createMcpServer.d.ts +3 -46
- package/dist/server/createMcpServer.d.ts.map +1 -1
- package/dist/server/createPermissionBasedMcpServer.d.ts +2 -64
- package/dist/server/createPermissionBasedMcpServer.d.ts.map +1 -1
- package/dist/server/server.types.d.ts +71 -0
- package/dist/server/server.types.d.ts.map +1 -0
- package/dist/server/server.utils.d.ts +45 -0
- package/dist/server/server.utils.d.ts.map +1 -0
- package/dist/session/ClientResourceCache.d.ts +8 -27
- package/dist/session/ClientResourceCache.d.ts.map +1 -1
- package/dist/session/SessionContextResolver.d.ts +21 -72
- package/dist/session/SessionContextResolver.d.ts.map +1 -1
- package/dist/session/session.types.d.ts +29 -0
- package/dist/session/session.types.d.ts.map +1 -0
- package/dist/session/{validateSessionContextConfig.d.ts → session.utils.d.ts} +1 -2
- package/dist/session/session.utils.d.ts.map +1 -0
- package/dist/types/index.d.ts +0 -24
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/http/customEndpoints.d.ts.map +0 -1
- package/dist/http/endpointRegistration.d.ts +0 -35
- package/dist/http/endpointRegistration.d.ts.map +0 -1
- package/dist/permissions/createPermissionAwareBundle.d.ts.map +0 -1
- package/dist/permissions/validatePermissionConfig.d.ts +0 -9
- package/dist/permissions/validatePermissionConfig.d.ts.map +0 -1
- package/dist/session/validateSessionContextConfig.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,70 +1,71 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
throw TypeError(
|
|
1
|
+
var ge = Object.defineProperty;
|
|
2
|
+
var H = (r) => {
|
|
3
|
+
throw TypeError(r);
|
|
4
4
|
};
|
|
5
|
-
var
|
|
6
|
-
var d = (
|
|
7
|
-
var
|
|
8
|
-
var m = (
|
|
9
|
-
import { z as
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
import { randomUUID as
|
|
13
|
-
import { StreamableHTTPServerTransport as
|
|
14
|
-
import { isInitializeRequest as
|
|
15
|
-
const
|
|
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
|
|
22
|
+
}, W = ["_meta"];
|
|
23
|
+
class L {
|
|
24
24
|
constructor(e = {}) {
|
|
25
25
|
d(this, "keys");
|
|
26
26
|
this.keys = {
|
|
27
|
-
dynamic: e.keys?.dynamic ??
|
|
28
|
-
toolsets: e.keys?.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((
|
|
37
|
-
for (const
|
|
38
|
-
|
|
39
|
-
`Invalid toolset '${
|
|
40
|
-
|
|
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
|
|
54
|
+
return n;
|
|
44
55
|
}
|
|
45
56
|
getModulesForToolSets(e, t) {
|
|
46
57
|
const s = /* @__PURE__ */ new Set();
|
|
47
|
-
for (const
|
|
48
|
-
const
|
|
49
|
-
|
|
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
|
-
*
|
|
76
|
-
*
|
|
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
|
|
84
|
-
if (!t[
|
|
97
|
+
for (const o of e)
|
|
98
|
+
if (!t[o])
|
|
85
99
|
return {
|
|
86
100
|
isValid: !1,
|
|
87
|
-
error: `Toolset '${
|
|
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
|
|
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
|
|
151
|
-
const
|
|
152
|
-
|
|
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
|
|
171
|
-
constructor(t, s,
|
|
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 =
|
|
227
|
+
this.name = "ToolingError", this.code = s, this.details = o;
|
|
176
228
|
}
|
|
177
229
|
}
|
|
178
|
-
class
|
|
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
|
|
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
|
|
209
|
-
if (this.has(
|
|
210
|
-
throw new
|
|
211
|
-
`Tool name collision for '${
|
|
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:
|
|
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
|
|
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 ??
|
|
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
|
|
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.
|
|
273
|
-
if (
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
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.
|
|
290
|
-
|
|
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
|
|
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 '${
|
|
369
|
+
message: `Failed to enable toolset '${o}': ${a instanceof Error ? a.message : "Unknown error"}`
|
|
311
370
|
};
|
|
312
371
|
}
|
|
313
372
|
}
|
|
314
373
|
/**
|
|
315
|
-
*
|
|
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 (
|
|
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 (
|
|
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
|
|
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: ${
|
|
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
|
|
500
|
+
for (const i of e)
|
|
399
501
|
try {
|
|
400
|
-
const a = await this.enableToolset(
|
|
401
|
-
t.push({ name:
|
|
502
|
+
const a = await this.enableToolset(i, !0);
|
|
503
|
+
t.push({ name: i, ...a });
|
|
402
504
|
} catch (a) {
|
|
403
505
|
t.push({
|
|
404
|
-
name:
|
|
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((
|
|
411
|
-
return
|
|
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
|
-
|
|
423
|
-
|
|
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:
|
|
528
|
+
{ name: g.string().describe("Toolset name") },
|
|
427
529
|
{ destructiveHint: !0, idempotentHint: !0 },
|
|
428
|
-
async (
|
|
429
|
-
const i = await e.enableToolset(
|
|
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
|
-
),
|
|
536
|
+
), t.addForToolset(T, "disable_toolset"), r.tool(
|
|
435
537
|
"disable_toolset",
|
|
436
538
|
"Disable a toolset by name (state only)",
|
|
437
|
-
{ name:
|
|
539
|
+
{ name: g.string().describe("Toolset name") },
|
|
438
540
|
{ destructiveHint: !0, idempotentHint: !0 },
|
|
439
|
-
async (
|
|
440
|
-
const i = await e.disableToolset(
|
|
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
|
-
),
|
|
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
|
|
452
|
-
const c = e.getToolsetDefinition(
|
|
553
|
+
const n = e.getAvailableToolsets(), i = e.getStatus().toolsetToTools, a = n.map((l) => {
|
|
554
|
+
const c = e.getToolsetDefinition(l);
|
|
453
555
|
return {
|
|
454
|
-
key:
|
|
455
|
-
active: e.isActive(
|
|
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[
|
|
564
|
+
tools: i[l] ?? []
|
|
463
565
|
};
|
|
464
566
|
});
|
|
465
567
|
return {
|
|
466
568
|
content: [
|
|
467
|
-
{ type: "text", text: JSON.stringify({ toolsets:
|
|
569
|
+
{ type: "text", text: JSON.stringify({ toolsets: a }) }
|
|
468
570
|
]
|
|
469
571
|
};
|
|
470
572
|
}
|
|
471
|
-
),
|
|
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:
|
|
576
|
+
{ name: g.string().describe("Toolset name") },
|
|
475
577
|
{ readOnlyHint: !0, idempotentHint: !0 },
|
|
476
|
-
async (
|
|
477
|
-
const i = e.getToolsetDefinition(
|
|
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 '${
|
|
585
|
+
text: JSON.stringify({ error: `Unknown toolset '${n.name}'` })
|
|
484
586
|
}
|
|
485
587
|
]
|
|
486
588
|
};
|
|
487
|
-
const
|
|
488
|
-
key:
|
|
489
|
-
active: e.isActive(
|
|
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
|
|
598
|
+
tools: a[n.name] ?? []
|
|
497
599
|
};
|
|
498
600
|
return {
|
|
499
|
-
content: [{ type: "text", text: JSON.stringify(
|
|
601
|
+
content: [{ type: "text", text: JSON.stringify(l) }]
|
|
500
602
|
};
|
|
501
603
|
}
|
|
502
|
-
)),
|
|
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
|
|
509
|
-
tools:
|
|
510
|
-
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 =
|
|
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 =
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
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
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
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
|
|
620
|
-
class
|
|
749
|
+
var w, M;
|
|
750
|
+
const D = class D {
|
|
621
751
|
constructor(e = {}) {
|
|
622
|
-
|
|
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,
|
|
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,
|
|
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,
|
|
692
|
-
e -
|
|
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
|
-
|
|
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
|
-
|
|
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((
|
|
708
|
-
console.warn(`Error in cache eviction callback for key '${e}':`,
|
|
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
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
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 ${
|
|
862
|
+
`Custom endpoint ${n.method} ${n.path} conflicts with built-in MCP endpoint. Skipping registration.`
|
|
723
863
|
);
|
|
724
864
|
continue;
|
|
725
865
|
}
|
|
726
|
-
const
|
|
727
|
-
|
|
866
|
+
const l = n.method.toLowerCase();
|
|
867
|
+
r[l](i, async (c, u) => {
|
|
728
868
|
try {
|
|
729
|
-
const
|
|
730
|
-
let
|
|
731
|
-
if (
|
|
732
|
-
const
|
|
733
|
-
if (!
|
|
734
|
-
return
|
|
735
|
-
|
|
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
|
|
738
|
-
if (
|
|
739
|
-
const
|
|
740
|
-
if (!
|
|
741
|
-
return
|
|
742
|
-
|
|
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
|
|
745
|
-
if (
|
|
746
|
-
const
|
|
747
|
-
if (!
|
|
748
|
-
return
|
|
749
|
-
|
|
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
|
|
752
|
-
body:
|
|
753
|
-
query:
|
|
754
|
-
params:
|
|
755
|
-
headers:
|
|
756
|
-
clientId:
|
|
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
|
|
760
|
-
Object.assign(
|
|
899
|
+
const p = await s.contextExtractor(c);
|
|
900
|
+
Object.assign(K, p);
|
|
761
901
|
}
|
|
762
|
-
const
|
|
763
|
-
if (
|
|
764
|
-
const
|
|
765
|
-
return
|
|
766
|
-
`Response validation failed for ${
|
|
767
|
-
|
|
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 (
|
|
915
|
+
return B;
|
|
916
|
+
} catch (f) {
|
|
777
917
|
return console.error(
|
|
778
|
-
`Error in custom endpoint ${
|
|
779
|
-
|
|
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:
|
|
923
|
+
message: f instanceof Error ? f.message : "Internal server error"
|
|
784
924
|
}
|
|
785
925
|
};
|
|
786
926
|
}
|
|
787
927
|
});
|
|
788
928
|
}
|
|
789
929
|
}
|
|
790
|
-
function
|
|
791
|
-
return
|
|
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
|
-
|
|
800
|
-
|
|
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
|
|
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 =
|
|
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 =
|
|
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 ??
|
|
827
|
-
this.options.cors && await e.register(
|
|
828
|
-
const t = this.
|
|
829
|
-
e.
|
|
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
|
-
}))
|
|
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,
|
|
841
|
-
const
|
|
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
|
-
|
|
1075
|
+
i
|
|
844
1076
|
);
|
|
845
|
-
let
|
|
846
|
-
if (!
|
|
847
|
-
const
|
|
848
|
-
|
|
849
|
-
server:
|
|
850
|
-
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
|
-
},
|
|
1084
|
+
}, this.clientCache.set(a, c);
|
|
853
1085
|
}
|
|
854
|
-
const
|
|
855
|
-
let
|
|
856
|
-
if (
|
|
857
|
-
|
|
858
|
-
else if (!
|
|
859
|
-
const
|
|
860
|
-
|
|
861
|
-
sessionIdGenerator: () =>
|
|
862
|
-
onsessioninitialized: (
|
|
863
|
-
|
|
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
|
|
1099
|
+
await c.server.connect(f);
|
|
868
1100
|
} catch {
|
|
869
|
-
return
|
|
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
|
-
|
|
876
|
-
|
|
1107
|
+
f.onclose = () => {
|
|
1108
|
+
f?.sessionId && c.sessions.delete(f.sessionId);
|
|
877
1109
|
};
|
|
878
1110
|
} else
|
|
879
|
-
return
|
|
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
|
|
1116
|
+
return await f.handleRequest(
|
|
885
1117
|
s.raw,
|
|
886
|
-
|
|
1118
|
+
o.raw,
|
|
887
1119
|
s.body
|
|
888
|
-
),
|
|
1120
|
+
), o;
|
|
889
1121
|
}
|
|
890
|
-
)
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
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
|
|
900
|
-
const
|
|
901
|
-
return
|
|
902
|
-
})
|
|
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,
|
|
905
|
-
const
|
|
906
|
-
if (!
|
|
907
|
-
return
|
|
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(
|
|
916
|
-
if (!c || !
|
|
917
|
-
return
|
|
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
|
|
1169
|
+
if (typeof u.close == "function")
|
|
924
1170
|
try {
|
|
925
|
-
await
|
|
1171
|
+
await u.close();
|
|
926
1172
|
} catch {
|
|
927
1173
|
}
|
|
928
1174
|
} finally {
|
|
929
|
-
|
|
1175
|
+
u?.sessionId ? c.sessions.delete(u.sessionId) : c.sessions.delete(a);
|
|
930
1176
|
}
|
|
931
|
-
return
|
|
1177
|
+
return o.code(204).send(), o;
|
|
932
1178
|
}
|
|
933
|
-
)
|
|
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((
|
|
952
|
-
console.warn(`Error closing session ${t}:`,
|
|
1190
|
+
typeof s.close == "function" && s.close().catch((o) => {
|
|
1191
|
+
console.warn(`Error closing session ${t}:`, o);
|
|
953
1192
|
});
|
|
954
|
-
} catch (
|
|
955
|
-
console.warn(`Error closing session ${t}:`,
|
|
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
|
-
},
|
|
1213
|
+
}, o = this.sessionContextResolver.resolve(
|
|
980
1214
|
s,
|
|
981
1215
|
this.baseContext
|
|
982
1216
|
);
|
|
983
1217
|
return {
|
|
984
|
-
cacheKey:
|
|
985
|
-
mergedContext:
|
|
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,
|
|
999
|
-
typeof
|
|
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 [
|
|
1013
|
-
typeof
|
|
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
|
|
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
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
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(
|
|
1058
|
-
cacheKeySuffix: this.generateCacheKeySuffix(
|
|
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
|
|
1077
|
-
return typeof
|
|
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 [
|
|
1127
|
-
const
|
|
1128
|
-
typeof
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
) : s[
|
|
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
|
|
1148
|
-
s[
|
|
1149
|
-
const
|
|
1150
|
-
return
|
|
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
|
|
1154
|
-
|
|
1397
|
+
function X(r) {
|
|
1398
|
+
xe(r), Se(r), Ee(r), Ce(r), Ae(r);
|
|
1155
1399
|
}
|
|
1156
|
-
function
|
|
1157
|
-
if (!
|
|
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
|
|
1163
|
-
if (
|
|
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
|
|
1409
|
+
`enabled must be a boolean, got ${typeof r.enabled}`
|
|
1166
1410
|
);
|
|
1167
1411
|
}
|
|
1168
|
-
function
|
|
1169
|
-
if (
|
|
1170
|
-
if (typeof
|
|
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 (
|
|
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 (
|
|
1418
|
+
if (r.queryParam.encoding !== void 0 && r.queryParam.encoding !== "base64" && r.queryParam.encoding !== "json")
|
|
1175
1419
|
throw new Error(
|
|
1176
|
-
`Invalid queryParam.encoding: "${
|
|
1420
|
+
`Invalid queryParam.encoding: "${r.queryParam.encoding}". Must be "base64" or "json"`
|
|
1177
1421
|
);
|
|
1178
|
-
if (
|
|
1179
|
-
if (!Array.isArray(
|
|
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 <
|
|
1182
|
-
const t =
|
|
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
|
|
1192
|
-
if (
|
|
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
|
|
1198
|
-
if (
|
|
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: "${
|
|
1444
|
+
`Invalid merge strategy: "${r.merge}". Must be "shallow" or "deep"`
|
|
1201
1445
|
);
|
|
1202
1446
|
}
|
|
1203
|
-
const
|
|
1204
|
-
mode:
|
|
1205
|
-
toolsets:
|
|
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
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
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
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
)
|
|
1228
|
-
|
|
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(
|
|
1232
|
-
await
|
|
1471
|
+
if (r(t)) {
|
|
1472
|
+
await t.server.notification({
|
|
1233
1473
|
method: "notifications/tools/list_changed"
|
|
1234
1474
|
});
|
|
1235
1475
|
return;
|
|
1236
1476
|
}
|
|
1237
|
-
|
|
1238
|
-
} catch (
|
|
1239
|
-
if ((
|
|
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:",
|
|
1481
|
+
console.warn("Failed to send tools list changed notification:", s);
|
|
1242
1482
|
}
|
|
1243
|
-
}
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
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
|
|
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:
|
|
1279
|
-
start:
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
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
|
|
1288
|
-
|
|
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
|
|
1291
|
-
if (!
|
|
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
|
|
1297
|
-
if (!
|
|
1561
|
+
function De(r) {
|
|
1562
|
+
if (!r.source)
|
|
1298
1563
|
throw new Error('Permission source must be either "headers" or "config"');
|
|
1299
|
-
if (
|
|
1564
|
+
if (r.source !== "headers" && r.source !== "config")
|
|
1300
1565
|
throw new Error(
|
|
1301
|
-
`Invalid permission source: "${
|
|
1566
|
+
`Invalid permission source: "${r.source}". Must be either "headers" or "config"`
|
|
1302
1567
|
);
|
|
1303
1568
|
}
|
|
1304
|
-
function
|
|
1305
|
-
if (
|
|
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
|
|
1311
|
-
if (
|
|
1312
|
-
if (typeof
|
|
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
|
-
|
|
1581
|
+
Fe(r.staticMap);
|
|
1317
1582
|
}
|
|
1318
|
-
if (
|
|
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 (
|
|
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 (
|
|
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
|
|
1328
|
-
for (const [e, t] of Object.entries(
|
|
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
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
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
|
-
|
|
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
|
|
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,
|
|
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
|
-
(
|
|
1683
|
+
(o) => typeof o == "string" && o.trim().length > 0
|
|
1368
1684
|
);
|
|
1369
|
-
} catch (
|
|
1685
|
+
} catch (o) {
|
|
1370
1686
|
console.error(
|
|
1371
1687
|
`Unexpected error resolving permissions for client ${e}:`,
|
|
1372
|
-
|
|
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
|
-
|
|
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
|
|
1400
|
-
* @private
|
|
1705
|
+
* @returns Array of toolset names from headers
|
|
1401
1706
|
*/
|
|
1402
|
-
|
|
1707
|
+
te = function(e) {
|
|
1403
1708
|
if (!e)
|
|
1404
1709
|
return [];
|
|
1405
|
-
const t = m(this,
|
|
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
|
|
1422
|
-
* @private
|
|
1724
|
+
* @returns The header value if found
|
|
1423
1725
|
*/
|
|
1424
|
-
|
|
1726
|
+
se = function(e, t) {
|
|
1425
1727
|
if (e[t] !== void 0)
|
|
1426
1728
|
return e[t];
|
|
1427
|
-
for (const [s,
|
|
1729
|
+
for (const [s, o] of Object.entries(e))
|
|
1428
1730
|
if (s.toLowerCase() === t)
|
|
1429
|
-
return
|
|
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
|
-
|
|
1736
|
+
re = function(e) {
|
|
1439
1737
|
if (this.config.resolver) {
|
|
1440
|
-
const t = m(this,
|
|
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,
|
|
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
|
|
1455
|
-
* @private
|
|
1750
|
+
* @returns Array of toolset names if successful, null if resolver fails
|
|
1456
1751
|
*/
|
|
1457
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
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
|
|
1784
|
+
d(this, "clientCache", new E({
|
|
1523
1785
|
onEvict: (e, t) => {
|
|
1524
|
-
m(this,
|
|
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 =
|
|
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 ??
|
|
1544
|
-
this.options.cors && await e.register(
|
|
1545
|
-
const t = m(this,
|
|
1546
|
-
m(this,
|
|
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
|
|
1847
|
+
const o = m(this, h, R).call(this, s);
|
|
1549
1848
|
try {
|
|
1550
|
-
const
|
|
1849
|
+
const n = await this.createPermissionAwareBundle(o);
|
|
1551
1850
|
return {
|
|
1552
|
-
allowedToolsets:
|
|
1553
|
-
failedToolsets:
|
|
1851
|
+
allowedToolsets: n.allowedToolsets,
|
|
1852
|
+
failedToolsets: n.failedToolsets
|
|
1554
1853
|
};
|
|
1555
|
-
} catch (
|
|
1854
|
+
} catch (n) {
|
|
1556
1855
|
return console.warn(
|
|
1557
|
-
`Permission resolution failed for custom endpoint: ${
|
|
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
|
-
|
|
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
|
-
|
|
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((
|
|
1584
|
-
console.warn(`Error closing session ${t}:`,
|
|
1875
|
+
typeof s.close == "function" && s.close().catch((o) => {
|
|
1876
|
+
console.warn(`Error closing session ${t}:`, o);
|
|
1585
1877
|
});
|
|
1586
|
-
} catch (
|
|
1587
|
-
console.warn(`Error closing session ${t}:`,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1621
|
-
e.get(`${t}/.well-known/mcp-config`, async (s,
|
|
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
|
-
|
|
1919
|
+
ue = function(e, t) {
|
|
1639
1920
|
e.post(
|
|
1640
1921
|
`${t}/mcp`,
|
|
1641
|
-
async (s,
|
|
1642
|
-
const
|
|
1643
|
-
|
|
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
|
|
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:
|
|
1657
|
-
},
|
|
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
|
-
),
|
|
1952
|
+
), o.code(403), m(this, h, me).call(this, "Access denied");
|
|
1663
1953
|
}
|
|
1664
|
-
const
|
|
1665
|
-
let
|
|
1666
|
-
if (
|
|
1667
|
-
|
|
1668
|
-
else if (!
|
|
1669
|
-
const u =
|
|
1670
|
-
|
|
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: (
|
|
1673
|
-
a.sessions.set(
|
|
1962
|
+
onsessioninitialized: (f) => {
|
|
1963
|
+
a.sessions.set(f, c);
|
|
1674
1964
|
}
|
|
1675
1965
|
});
|
|
1676
1966
|
try {
|
|
1677
|
-
await a.server.connect(
|
|
1967
|
+
await a.server.connect(c);
|
|
1678
1968
|
} catch {
|
|
1679
|
-
return
|
|
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
|
-
|
|
1686
|
-
|
|
1975
|
+
c.onclose = () => {
|
|
1976
|
+
c?.sessionId && a.sessions.delete(c.sessionId);
|
|
1687
1977
|
};
|
|
1688
1978
|
} else
|
|
1689
|
-
return
|
|
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
|
|
1984
|
+
return await c.handleRequest(
|
|
1695
1985
|
s.raw,
|
|
1696
|
-
|
|
1986
|
+
o.raw,
|
|
1697
1987
|
s.body
|
|
1698
|
-
),
|
|
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
|
-
|
|
1708
|
-
e.get(`${t}/mcp`, async (s,
|
|
1709
|
-
const
|
|
1710
|
-
if (!
|
|
1711
|
-
return
|
|
1712
|
-
const a = this.clientCache.get(
|
|
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
|
|
1715
|
-
const
|
|
1716
|
-
if (!
|
|
1717
|
-
return
|
|
1718
|
-
const
|
|
1719
|
-
return
|
|
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
|
-
|
|
2013
|
+
fe = function(e, t) {
|
|
1728
2014
|
e.delete(
|
|
1729
2015
|
`${t}/mcp`,
|
|
1730
|
-
async (s,
|
|
1731
|
-
const
|
|
1732
|
-
if (!
|
|
1733
|
-
return
|
|
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
|
|
1742
|
-
if (!
|
|
1743
|
-
return
|
|
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
|
|
2035
|
+
if (typeof c.close == "function")
|
|
1750
2036
|
try {
|
|
1751
|
-
await
|
|
2037
|
+
await c.close();
|
|
1752
2038
|
} catch {
|
|
1753
2039
|
}
|
|
1754
2040
|
} finally {
|
|
1755
|
-
|
|
2041
|
+
c?.sessionId ? l.sessions.delete(c.sessionId) : l.sessions.delete(a);
|
|
1756
2042
|
}
|
|
1757
|
-
return
|
|
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
|
-
|
|
1768
|
-
const t = e.headers["mcp-client-id"]?.trim(), s = t && t.length > 0 ? t : `anon-${
|
|
1769
|
-
for (const [
|
|
1770
|
-
typeof
|
|
1771
|
-
return { clientId: s, headers:
|
|
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
|
|
2057
|
+
* @param code - JSON-RPC error code
|
|
1777
2058
|
* @returns JSON-RPC error response object
|
|
1778
|
-
* @private
|
|
1779
2059
|
*/
|
|
1780
|
-
|
|
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
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
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
|
-
|
|
1806
|
-
if (!
|
|
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 (
|
|
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
|
-
)),
|
|
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
|
|
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
|
|
1871
|
-
|
|
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
|
|
1874
|
-
|
|
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
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
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
|