toolception 0.2.5 → 0.3.0
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 +902 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +737 -262
- package/dist/index.js.map +1 -1
- package/dist/permissions/PermissionAwareFastifyTransport.d.ts +46 -0
- package/dist/permissions/PermissionAwareFastifyTransport.d.ts.map +1 -0
- package/dist/permissions/PermissionResolver.d.ts +31 -0
- package/dist/permissions/PermissionResolver.d.ts.map +1 -0
- package/dist/permissions/createPermissionAwareBundle.d.ts +52 -0
- package/dist/permissions/createPermissionAwareBundle.d.ts.map +1 -0
- package/dist/permissions/validatePermissionConfig.d.ts +9 -0
- package/dist/permissions/validatePermissionConfig.d.ts.map +1 -0
- package/dist/server/createPermissionBasedMcpServer.d.ts +65 -0
- package/dist/server/createPermissionBasedMcpServer.d.ts.map +1 -0
- package/dist/types/index.d.ts +229 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +6 -1
package/dist/index.js
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
var w = (r) => {
|
|
2
|
+
throw TypeError(r);
|
|
3
|
+
};
|
|
4
|
+
var B = (r, e, t) => e.has(r) || w("Cannot " + t);
|
|
5
|
+
var v = (r, e, t) => e.has(r) ? w("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(r) : e.set(r, t);
|
|
6
|
+
var u = (r, e, t) => (B(r, e, "access private method"), t);
|
|
7
|
+
import { z as T } from "zod";
|
|
8
|
+
import S from "fastify";
|
|
9
|
+
import M from "@fastify/cors";
|
|
10
|
+
import { randomUUID as p } from "node:crypto";
|
|
11
|
+
import { StreamableHTTPServerTransport as C } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
12
|
+
import { isInitializeRequest as x } from "@modelcontextprotocol/sdk/types.js";
|
|
13
|
+
const b = {
|
|
8
14
|
dynamic: [
|
|
9
15
|
"dynamic-tool-discovery",
|
|
10
16
|
"dynamicToolDiscovery",
|
|
@@ -12,89 +18,89 @@ const g = {
|
|
|
12
18
|
],
|
|
13
19
|
toolsets: ["tool-sets", "toolSets", "FMP_TOOL_SETS"]
|
|
14
20
|
};
|
|
15
|
-
class
|
|
21
|
+
class Y {
|
|
16
22
|
constructor(e = {}) {
|
|
17
23
|
this.keys = {
|
|
18
|
-
dynamic: e.keys?.dynamic ??
|
|
19
|
-
toolsets: e.keys?.toolsets ??
|
|
24
|
+
dynamic: e.keys?.dynamic ?? b.dynamic,
|
|
25
|
+
toolsets: e.keys?.toolsets ?? b.toolsets
|
|
20
26
|
};
|
|
21
27
|
}
|
|
22
|
-
resolveMode(e,
|
|
23
|
-
return this.isDynamicEnabled(
|
|
28
|
+
resolveMode(e, t) {
|
|
29
|
+
return this.isDynamicEnabled(t) ? "DYNAMIC" : this.getToolsetsString(t) ? "STATIC" : this.isDynamicEnabled(e) ? "DYNAMIC" : this.getToolsetsString(e) ? "STATIC" : null;
|
|
24
30
|
}
|
|
25
|
-
parseCommaSeparatedToolSets(e,
|
|
31
|
+
parseCommaSeparatedToolSets(e, t) {
|
|
26
32
|
if (!e || typeof e != "string") return [];
|
|
27
|
-
const
|
|
28
|
-
for (const
|
|
29
|
-
o.has(
|
|
30
|
-
`Invalid toolset '${
|
|
33
|
+
const s = e.split(",").map((a) => a.trim()).filter((a) => a.length > 0), o = new Set(Object.keys(t)), i = [];
|
|
34
|
+
for (const a of s)
|
|
35
|
+
o.has(a) ? i.push(a) : console.warn(
|
|
36
|
+
`Invalid toolset '${a}' ignored. Available: ${Array.from(
|
|
31
37
|
o
|
|
32
38
|
).join(", ")}`
|
|
33
39
|
);
|
|
34
|
-
return
|
|
40
|
+
return i;
|
|
35
41
|
}
|
|
36
|
-
getModulesForToolSets(e,
|
|
37
|
-
const
|
|
42
|
+
getModulesForToolSets(e, t) {
|
|
43
|
+
const s = /* @__PURE__ */ new Set();
|
|
38
44
|
for (const o of e) {
|
|
39
|
-
const
|
|
40
|
-
|
|
45
|
+
const i = t[o];
|
|
46
|
+
i && (i.modules || []).forEach((a) => s.add(a));
|
|
41
47
|
}
|
|
42
|
-
return Array.from(
|
|
48
|
+
return Array.from(s);
|
|
43
49
|
}
|
|
44
|
-
validateToolsetName(e,
|
|
50
|
+
validateToolsetName(e, t) {
|
|
45
51
|
if (!e || typeof e != "string")
|
|
46
52
|
return {
|
|
47
53
|
isValid: !1,
|
|
48
54
|
error: `Invalid toolset name provided. Must be a non-empty string. Available toolsets: ${Object.keys(
|
|
49
|
-
|
|
55
|
+
t
|
|
50
56
|
).join(", ")}`
|
|
51
57
|
};
|
|
52
|
-
const
|
|
53
|
-
return
|
|
58
|
+
const s = e.trim();
|
|
59
|
+
return s.length === 0 ? {
|
|
54
60
|
isValid: !1,
|
|
55
61
|
error: `Empty toolset name provided. Available toolsets: ${Object.keys(
|
|
56
|
-
|
|
62
|
+
t
|
|
57
63
|
).join(", ")}`
|
|
58
|
-
} : s
|
|
64
|
+
} : t[s] ? { isValid: !0, sanitized: s } : {
|
|
59
65
|
isValid: !1,
|
|
60
|
-
error: `Toolset '${
|
|
61
|
-
|
|
66
|
+
error: `Toolset '${s}' not found. Available toolsets: ${Object.keys(
|
|
67
|
+
t
|
|
62
68
|
).join(", ")}`
|
|
63
69
|
};
|
|
64
70
|
}
|
|
65
|
-
validateToolsetModules(e,
|
|
71
|
+
validateToolsetModules(e, t) {
|
|
66
72
|
try {
|
|
67
|
-
const
|
|
68
|
-
return !
|
|
73
|
+
const s = this.getModulesForToolSets(e, t);
|
|
74
|
+
return !s || s.length === 0 ? {
|
|
69
75
|
isValid: !1,
|
|
70
76
|
error: `No modules found for toolsets: ${e.join(", ")}`
|
|
71
|
-
} : { isValid: !0, modules:
|
|
72
|
-
} catch (
|
|
77
|
+
} : { isValid: !0, modules: s };
|
|
78
|
+
} catch (s) {
|
|
73
79
|
return {
|
|
74
80
|
isValid: !1,
|
|
75
|
-
error: `Error resolving modules for ${e.join(", ")}: ${
|
|
81
|
+
error: `Error resolving modules for ${e.join(", ")}: ${s instanceof Error ? s.message : "Unknown error"}`
|
|
76
82
|
};
|
|
77
83
|
}
|
|
78
84
|
}
|
|
79
85
|
isDynamicEnabled(e) {
|
|
80
86
|
if (!e) return !1;
|
|
81
|
-
for (const
|
|
82
|
-
const
|
|
83
|
-
if (
|
|
87
|
+
for (const t of this.keys.dynamic) {
|
|
88
|
+
const s = e[t];
|
|
89
|
+
if (s === !0 || typeof s == "string" && s.trim().toLowerCase() === "true")
|
|
84
90
|
return !0;
|
|
85
91
|
}
|
|
86
92
|
return !1;
|
|
87
93
|
}
|
|
88
94
|
getToolsetsString(e) {
|
|
89
95
|
if (e)
|
|
90
|
-
for (const
|
|
91
|
-
const
|
|
92
|
-
if (typeof
|
|
93
|
-
return
|
|
96
|
+
for (const t of this.keys.toolsets) {
|
|
97
|
+
const s = e[t];
|
|
98
|
+
if (typeof s == "string" && s.trim().length > 0)
|
|
99
|
+
return s;
|
|
94
100
|
}
|
|
95
101
|
}
|
|
96
102
|
}
|
|
97
|
-
class
|
|
103
|
+
class U {
|
|
98
104
|
constructor(e) {
|
|
99
105
|
this.catalog = e.catalog, this.moduleLoaders = e.moduleLoaders ?? {};
|
|
100
106
|
}
|
|
@@ -112,80 +118,80 @@ class x {
|
|
|
112
118
|
", "
|
|
113
119
|
)}`
|
|
114
120
|
};
|
|
115
|
-
const
|
|
116
|
-
return
|
|
121
|
+
const t = e.trim();
|
|
122
|
+
return t.length === 0 ? {
|
|
117
123
|
isValid: !1,
|
|
118
124
|
error: `Empty toolset name provided. Available toolsets: ${this.getAvailableToolsets().join(
|
|
119
125
|
", "
|
|
120
126
|
)}`
|
|
121
|
-
} : this.catalog[
|
|
127
|
+
} : this.catalog[t] ? { isValid: !0, sanitized: t } : {
|
|
122
128
|
isValid: !1,
|
|
123
|
-
error: `Toolset '${
|
|
129
|
+
error: `Toolset '${t}' not found. Available toolsets: ${this.getAvailableToolsets().join(
|
|
124
130
|
", "
|
|
125
131
|
)}`
|
|
126
132
|
};
|
|
127
133
|
}
|
|
128
|
-
async resolveToolsForToolsets(e,
|
|
129
|
-
const
|
|
134
|
+
async resolveToolsForToolsets(e, t) {
|
|
135
|
+
const s = [];
|
|
130
136
|
for (const o of e) {
|
|
131
|
-
const
|
|
132
|
-
if (
|
|
133
|
-
for (const
|
|
134
|
-
const l = this.moduleLoaders[
|
|
137
|
+
const i = this.catalog[o];
|
|
138
|
+
if (i && (Array.isArray(i.tools) && i.tools.length > 0 && s.push(...i.tools), Array.isArray(i.modules) && i.modules.length > 0))
|
|
139
|
+
for (const a of i.modules) {
|
|
140
|
+
const l = this.moduleLoaders[a];
|
|
135
141
|
if (l)
|
|
136
142
|
try {
|
|
137
|
-
const n = await l(
|
|
138
|
-
Array.isArray(n) && n.length > 0 &&
|
|
143
|
+
const n = await l(t);
|
|
144
|
+
Array.isArray(n) && n.length > 0 && s.push(...n);
|
|
139
145
|
} catch (n) {
|
|
140
146
|
console.warn(
|
|
141
|
-
`Module loader '${
|
|
147
|
+
`Module loader '${a}' failed for toolset '${o}':`,
|
|
142
148
|
n
|
|
143
149
|
);
|
|
144
150
|
}
|
|
145
151
|
}
|
|
146
152
|
}
|
|
147
|
-
return
|
|
153
|
+
return s;
|
|
148
154
|
}
|
|
149
155
|
}
|
|
150
|
-
class
|
|
151
|
-
constructor(e,
|
|
152
|
-
super(e), this.name = "ToolingError", this.code =
|
|
156
|
+
class A extends Error {
|
|
157
|
+
constructor(e, t, s, o) {
|
|
158
|
+
super(e), this.name = "ToolingError", this.code = t, this.details = s;
|
|
153
159
|
}
|
|
154
160
|
}
|
|
155
|
-
class
|
|
161
|
+
class I {
|
|
156
162
|
constructor(e = {}) {
|
|
157
163
|
this.names = /* @__PURE__ */ new Set(), this.toolsetToNames = /* @__PURE__ */ new Map(), this.options = {
|
|
158
164
|
namespaceWithToolset: e.namespaceWithToolset ?? !0
|
|
159
165
|
};
|
|
160
166
|
}
|
|
161
|
-
getSafeName(e,
|
|
162
|
-
return !this.options.namespaceWithToolset ||
|
|
167
|
+
getSafeName(e, t) {
|
|
168
|
+
return !this.options.namespaceWithToolset || t.startsWith(`${e}.`) ? t : `${e}.${t}`;
|
|
163
169
|
}
|
|
164
170
|
has(e) {
|
|
165
171
|
return this.names.has(e);
|
|
166
172
|
}
|
|
167
173
|
add(e) {
|
|
168
174
|
if (this.names.has(e))
|
|
169
|
-
throw new
|
|
175
|
+
throw new A(
|
|
170
176
|
`Tool name collision: '${e}' already registered`,
|
|
171
177
|
"E_TOOL_NAME_CONFLICT"
|
|
172
178
|
);
|
|
173
179
|
this.names.add(e);
|
|
174
180
|
}
|
|
175
|
-
addForToolset(e,
|
|
176
|
-
this.add(
|
|
177
|
-
const
|
|
178
|
-
|
|
181
|
+
addForToolset(e, t) {
|
|
182
|
+
this.add(t);
|
|
183
|
+
const s = this.toolsetToNames.get(e) ?? /* @__PURE__ */ new Set();
|
|
184
|
+
s.add(t), this.toolsetToNames.set(e, s);
|
|
179
185
|
}
|
|
180
|
-
mapAndValidate(e,
|
|
181
|
-
return
|
|
182
|
-
const o = this.getSafeName(e,
|
|
186
|
+
mapAndValidate(e, t) {
|
|
187
|
+
return t.map((s) => {
|
|
188
|
+
const o = this.getSafeName(e, s.name);
|
|
183
189
|
if (this.has(o))
|
|
184
|
-
throw new
|
|
190
|
+
throw new A(
|
|
185
191
|
`Tool name collision for '${o}'`,
|
|
186
192
|
"E_TOOL_NAME_CONFLICT"
|
|
187
193
|
);
|
|
188
|
-
return { ...
|
|
194
|
+
return { ...s, name: o };
|
|
189
195
|
});
|
|
190
196
|
}
|
|
191
197
|
list() {
|
|
@@ -193,14 +199,14 @@ class v {
|
|
|
193
199
|
}
|
|
194
200
|
listByToolset() {
|
|
195
201
|
const e = {};
|
|
196
|
-
for (const [
|
|
197
|
-
e[
|
|
202
|
+
for (const [t, s] of this.toolsetToNames.entries())
|
|
203
|
+
e[t] = Array.from(s);
|
|
198
204
|
return e;
|
|
199
205
|
}
|
|
200
206
|
}
|
|
201
|
-
class
|
|
207
|
+
class W {
|
|
202
208
|
constructor(e) {
|
|
203
|
-
this.activeToolsets = /* @__PURE__ */ new Set(), this.server = e.server, this.resolver = e.resolver, this.context = e.context, this.onToolsListChanged = e.onToolsListChanged, this.exposurePolicy = e.exposurePolicy, this.toolRegistry = e.toolRegistry ?? new
|
|
209
|
+
this.activeToolsets = /* @__PURE__ */ new Set(), this.server = e.server, this.resolver = e.resolver, this.context = e.context, this.onToolsListChanged = e.onToolsListChanged, this.exposurePolicy = e.exposurePolicy, this.toolRegistry = e.toolRegistry ?? new I({ namespaceWithToolset: !0 });
|
|
204
210
|
}
|
|
205
211
|
getAvailableToolsets() {
|
|
206
212
|
return this.resolver.getAvailableToolsets();
|
|
@@ -215,81 +221,81 @@ class C {
|
|
|
215
221
|
return this.activeToolsets.has(e);
|
|
216
222
|
}
|
|
217
223
|
async enableToolset(e) {
|
|
218
|
-
const
|
|
219
|
-
if (!
|
|
224
|
+
const t = this.resolver.validateToolsetName(e);
|
|
225
|
+
if (!t.isValid || !t.sanitized)
|
|
220
226
|
return {
|
|
221
227
|
success: !1,
|
|
222
|
-
message:
|
|
228
|
+
message: t.error || "Unknown validation error"
|
|
223
229
|
};
|
|
224
|
-
const
|
|
225
|
-
if (this.activeToolsets.has(
|
|
230
|
+
const s = t.sanitized;
|
|
231
|
+
if (this.activeToolsets.has(s))
|
|
226
232
|
return {
|
|
227
233
|
success: !1,
|
|
228
|
-
message: `Toolset '${
|
|
234
|
+
message: `Toolset '${s}' is already enabled.`
|
|
229
235
|
};
|
|
230
236
|
try {
|
|
231
237
|
const o = await this.resolver.resolveToolsForToolsets(
|
|
232
|
-
[
|
|
238
|
+
[s],
|
|
233
239
|
this.context
|
|
234
240
|
);
|
|
235
|
-
if (this.exposurePolicy?.allowlist && !this.exposurePolicy.allowlist.includes(
|
|
241
|
+
if (this.exposurePolicy?.allowlist && !this.exposurePolicy.allowlist.includes(s))
|
|
236
242
|
return {
|
|
237
243
|
success: !1,
|
|
238
|
-
message: `Toolset '${
|
|
244
|
+
message: `Toolset '${s}' is not allowed by policy.`
|
|
239
245
|
};
|
|
240
|
-
if (this.exposurePolicy?.denylist && this.exposurePolicy.denylist.includes(
|
|
246
|
+
if (this.exposurePolicy?.denylist && this.exposurePolicy.denylist.includes(s))
|
|
241
247
|
return {
|
|
242
248
|
success: !1,
|
|
243
|
-
message: `Toolset '${
|
|
249
|
+
message: `Toolset '${s}' is denied by policy.`
|
|
244
250
|
};
|
|
245
251
|
if (this.exposurePolicy?.maxActiveToolsets !== void 0 && this.activeToolsets.size + 1 > this.exposurePolicy.maxActiveToolsets)
|
|
246
252
|
return this.exposurePolicy.onLimitExceeded?.(
|
|
247
|
-
[
|
|
253
|
+
[s],
|
|
248
254
|
Array.from(this.activeToolsets)
|
|
249
255
|
), {
|
|
250
256
|
success: !1,
|
|
251
257
|
message: `Activation exceeds maxActiveToolsets (${this.exposurePolicy.maxActiveToolsets}).`
|
|
252
258
|
};
|
|
253
259
|
if (o && o.length > 0) {
|
|
254
|
-
const
|
|
255
|
-
|
|
260
|
+
const i = this.toolRegistry.mapAndValidate(
|
|
261
|
+
s,
|
|
256
262
|
o
|
|
257
263
|
);
|
|
258
|
-
this.registerDirectTools(
|
|
264
|
+
this.registerDirectTools(i, s);
|
|
259
265
|
}
|
|
260
|
-
this.activeToolsets.add(
|
|
266
|
+
this.activeToolsets.add(s);
|
|
261
267
|
try {
|
|
262
268
|
await this.onToolsListChanged?.();
|
|
263
|
-
} catch (
|
|
264
|
-
console.warn("Failed to send tool list change notification:",
|
|
269
|
+
} catch (i) {
|
|
270
|
+
console.warn("Failed to send tool list change notification:", i);
|
|
265
271
|
}
|
|
266
272
|
return {
|
|
267
273
|
success: !0,
|
|
268
|
-
message: `Toolset '${
|
|
274
|
+
message: `Toolset '${s}' enabled successfully. Registered ${o?.length ?? 0} tools.`
|
|
269
275
|
};
|
|
270
276
|
} catch (o) {
|
|
271
|
-
return this.activeToolsets.delete(
|
|
277
|
+
return this.activeToolsets.delete(s), {
|
|
272
278
|
success: !1,
|
|
273
|
-
message: `Failed to enable toolset '${
|
|
279
|
+
message: `Failed to enable toolset '${s}': ${o instanceof Error ? o.message : "Unknown error"}`
|
|
274
280
|
};
|
|
275
281
|
}
|
|
276
282
|
}
|
|
277
283
|
async disableToolset(e) {
|
|
278
|
-
const
|
|
279
|
-
if (!
|
|
284
|
+
const t = this.resolver.validateToolsetName(e);
|
|
285
|
+
if (!t.isValid || !t.sanitized) {
|
|
280
286
|
const o = Array.from(this.activeToolsets).join(", ") || "none";
|
|
281
287
|
return {
|
|
282
288
|
success: !1,
|
|
283
|
-
message: `${
|
|
289
|
+
message: `${t.error || "Unknown validation error"} Active toolsets: ${o}`
|
|
284
290
|
};
|
|
285
291
|
}
|
|
286
|
-
const
|
|
287
|
-
if (!this.activeToolsets.has(
|
|
292
|
+
const s = t.sanitized;
|
|
293
|
+
if (!this.activeToolsets.has(s))
|
|
288
294
|
return {
|
|
289
295
|
success: !1,
|
|
290
|
-
message: `Toolset '${
|
|
296
|
+
message: `Toolset '${s}' is not currently active. Active toolsets: ${Array.from(this.activeToolsets).join(", ") || "none"}`
|
|
291
297
|
};
|
|
292
|
-
this.activeToolsets.delete(
|
|
298
|
+
this.activeToolsets.delete(s);
|
|
293
299
|
try {
|
|
294
300
|
await this.onToolsListChanged?.();
|
|
295
301
|
} catch (o) {
|
|
@@ -297,7 +303,7 @@ class C {
|
|
|
297
303
|
}
|
|
298
304
|
return {
|
|
299
305
|
success: !0,
|
|
300
|
-
message: `Toolset '${
|
|
306
|
+
message: `Toolset '${s}' disabled successfully. Individual tools remain registered due to MCP limitations.`
|
|
301
307
|
};
|
|
302
308
|
}
|
|
303
309
|
getStatus() {
|
|
@@ -312,38 +318,38 @@ class C {
|
|
|
312
318
|
};
|
|
313
319
|
}
|
|
314
320
|
async enableToolsets(e) {
|
|
315
|
-
const
|
|
316
|
-
for (const
|
|
321
|
+
const t = [];
|
|
322
|
+
for (const i of e)
|
|
317
323
|
try {
|
|
318
|
-
const
|
|
319
|
-
|
|
320
|
-
} catch (
|
|
321
|
-
|
|
322
|
-
name:
|
|
324
|
+
const a = await this.enableToolset(i);
|
|
325
|
+
t.push({ name: i, ...a });
|
|
326
|
+
} catch (a) {
|
|
327
|
+
t.push({
|
|
328
|
+
name: i,
|
|
323
329
|
success: !1,
|
|
324
|
-
message:
|
|
330
|
+
message: a instanceof Error ? a.message : "Unknown error",
|
|
325
331
|
code: "E_INTERNAL"
|
|
326
332
|
});
|
|
327
333
|
}
|
|
328
|
-
const
|
|
329
|
-
if (
|
|
334
|
+
const s = t.every((i) => i.success), o = s ? "All toolsets enabled" : "Some toolsets failed to enable";
|
|
335
|
+
if (t.length > 0)
|
|
330
336
|
try {
|
|
331
337
|
await this.onToolsListChanged?.();
|
|
332
338
|
} catch {
|
|
333
339
|
}
|
|
334
|
-
return { success:
|
|
340
|
+
return { success: s, results: t, message: o };
|
|
335
341
|
}
|
|
336
|
-
registerDirectTools(e,
|
|
337
|
-
for (const
|
|
342
|
+
registerDirectTools(e, t) {
|
|
343
|
+
for (const s of e)
|
|
338
344
|
try {
|
|
339
345
|
this.server.tool(
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
async (o) => await
|
|
344
|
-
),
|
|
346
|
+
s.name,
|
|
347
|
+
s.description,
|
|
348
|
+
s.inputSchema,
|
|
349
|
+
async (o) => await s.handler(o)
|
|
350
|
+
), t ? this.toolRegistry.addForToolset(t, s.name) : this.toolRegistry.add(s.name);
|
|
345
351
|
} catch (o) {
|
|
346
|
-
throw console.error(`Failed to register direct tool '${
|
|
352
|
+
throw console.error(`Failed to register direct tool '${s.name}':`, o), o;
|
|
347
353
|
}
|
|
348
354
|
}
|
|
349
355
|
async enableAllToolsets() {
|
|
@@ -351,34 +357,34 @@ class C {
|
|
|
351
357
|
return this.enableToolsets(e);
|
|
352
358
|
}
|
|
353
359
|
}
|
|
354
|
-
function
|
|
355
|
-
const
|
|
356
|
-
|
|
360
|
+
function H(r, e, t) {
|
|
361
|
+
const s = t?.mode ?? "DYNAMIC";
|
|
362
|
+
r.tool(
|
|
357
363
|
"enable_toolset",
|
|
358
364
|
"Enable a toolset by name",
|
|
359
|
-
{ name:
|
|
365
|
+
{ name: T.string().describe("Toolset name") },
|
|
360
366
|
async (o) => {
|
|
361
|
-
const { name:
|
|
367
|
+
const { name: i } = o, a = await e.enableToolset(i);
|
|
362
368
|
return {
|
|
363
|
-
content: [{ type: "text", text: JSON.stringify(
|
|
369
|
+
content: [{ type: "text", text: JSON.stringify(a) }]
|
|
364
370
|
};
|
|
365
371
|
}
|
|
366
|
-
),
|
|
372
|
+
), r.tool(
|
|
367
373
|
"disable_toolset",
|
|
368
374
|
"Disable a toolset by name (state only)",
|
|
369
|
-
{ name:
|
|
375
|
+
{ name: T.string().describe("Toolset name") },
|
|
370
376
|
async (o) => {
|
|
371
|
-
const { name:
|
|
377
|
+
const { name: i } = o, a = await e.disableToolset(i);
|
|
372
378
|
return {
|
|
373
|
-
content: [{ type: "text", text: JSON.stringify(
|
|
379
|
+
content: [{ type: "text", text: JSON.stringify(a) }]
|
|
374
380
|
};
|
|
375
381
|
}
|
|
376
|
-
),
|
|
382
|
+
), s === "DYNAMIC" && (r.tool(
|
|
377
383
|
"list_toolsets",
|
|
378
384
|
"List available toolsets with active status and definitions",
|
|
379
385
|
{},
|
|
380
386
|
async () => {
|
|
381
|
-
const o = e.getAvailableToolsets(),
|
|
387
|
+
const o = e.getAvailableToolsets(), i = e.getStatus().toolsetToTools, a = o.map((l) => {
|
|
382
388
|
const n = e.getToolsetDefinition(l);
|
|
383
389
|
return {
|
|
384
390
|
key: l,
|
|
@@ -389,95 +395,95 @@ function I(a, e, s) {
|
|
|
389
395
|
modules: n.modules ?? [],
|
|
390
396
|
decisionCriteria: n.decisionCriteria ?? void 0
|
|
391
397
|
} : null,
|
|
392
|
-
tools:
|
|
398
|
+
tools: i[l] ?? []
|
|
393
399
|
};
|
|
394
400
|
});
|
|
395
401
|
return {
|
|
396
402
|
content: [
|
|
397
|
-
{ type: "text", text: JSON.stringify({ toolsets:
|
|
403
|
+
{ type: "text", text: JSON.stringify({ toolsets: a }) }
|
|
398
404
|
]
|
|
399
405
|
};
|
|
400
406
|
}
|
|
401
|
-
),
|
|
407
|
+
), r.tool(
|
|
402
408
|
"describe_toolset",
|
|
403
409
|
"Describe a toolset with definition, active status and tools",
|
|
404
|
-
{ name:
|
|
410
|
+
{ name: T.string().describe("Toolset name") },
|
|
405
411
|
async (o) => {
|
|
406
|
-
const { name:
|
|
407
|
-
if (!
|
|
412
|
+
const { name: i } = o, a = e.getToolsetDefinition(i), l = e.getStatus().toolsetToTools;
|
|
413
|
+
if (!a)
|
|
408
414
|
return {
|
|
409
415
|
content: [
|
|
410
416
|
{
|
|
411
417
|
type: "text",
|
|
412
|
-
text: JSON.stringify({ error: `Unknown toolset '${
|
|
418
|
+
text: JSON.stringify({ error: `Unknown toolset '${i}'` })
|
|
413
419
|
}
|
|
414
420
|
]
|
|
415
421
|
};
|
|
416
422
|
const n = {
|
|
417
|
-
key:
|
|
418
|
-
active: e.isActive(
|
|
423
|
+
key: i,
|
|
424
|
+
active: e.isActive(i),
|
|
419
425
|
definition: {
|
|
420
|
-
name:
|
|
421
|
-
description:
|
|
422
|
-
modules:
|
|
423
|
-
decisionCriteria:
|
|
426
|
+
name: a.name,
|
|
427
|
+
description: a.description,
|
|
428
|
+
modules: a.modules ?? [],
|
|
429
|
+
decisionCriteria: a.decisionCriteria ?? void 0
|
|
424
430
|
},
|
|
425
|
-
tools: l[
|
|
431
|
+
tools: l[i] ?? []
|
|
426
432
|
};
|
|
427
433
|
return {
|
|
428
434
|
content: [{ type: "text", text: JSON.stringify(n) }]
|
|
429
435
|
};
|
|
430
436
|
}
|
|
431
|
-
)),
|
|
437
|
+
)), r.tool(
|
|
432
438
|
"list_tools",
|
|
433
439
|
"List currently registered tool names (best effort)",
|
|
434
440
|
{},
|
|
435
441
|
async () => {
|
|
436
|
-
const o = e.getStatus(),
|
|
442
|
+
const o = e.getStatus(), i = {
|
|
437
443
|
tools: o.tools,
|
|
438
444
|
toolsetToTools: o.toolsetToTools
|
|
439
445
|
};
|
|
440
446
|
return {
|
|
441
|
-
content: [{ type: "text", text: JSON.stringify(
|
|
447
|
+
content: [{ type: "text", text: JSON.stringify(i) }]
|
|
442
448
|
};
|
|
443
449
|
}
|
|
444
450
|
);
|
|
445
451
|
}
|
|
446
452
|
class y {
|
|
447
453
|
constructor(e) {
|
|
448
|
-
this.toolsetValidator = new
|
|
449
|
-
const
|
|
450
|
-
this.mode =
|
|
454
|
+
this.toolsetValidator = new Y();
|
|
455
|
+
const t = e.startup ?? {}, s = this.resolveStartupConfig(t, e.catalog);
|
|
456
|
+
this.mode = s.mode, this.resolver = new U({
|
|
451
457
|
catalog: e.catalog,
|
|
452
458
|
moduleLoaders: e.moduleLoaders
|
|
453
459
|
});
|
|
454
|
-
const o = new
|
|
460
|
+
const o = new I({
|
|
455
461
|
namespaceWithToolset: e.exposurePolicy?.namespaceToolsWithSetKey ?? !0
|
|
456
462
|
});
|
|
457
|
-
this.manager = new
|
|
463
|
+
this.manager = new W({
|
|
458
464
|
server: e.server,
|
|
459
465
|
resolver: this.resolver,
|
|
460
466
|
context: e.context,
|
|
461
467
|
onToolsListChanged: e.notifyToolsListChanged,
|
|
462
468
|
exposurePolicy: e.exposurePolicy,
|
|
463
469
|
toolRegistry: o
|
|
464
|
-
}), e.registerMetaTools !== !1 &&
|
|
465
|
-
const
|
|
466
|
-
|
|
470
|
+
}), e.registerMetaTools !== !1 && H(e.server, this.manager, { mode: this.mode });
|
|
471
|
+
const i = s.toolsets;
|
|
472
|
+
i === "ALL" ? this.manager.enableToolsets(this.resolver.getAvailableToolsets()) : Array.isArray(i) && i.length > 0 && this.manager.enableToolsets(i);
|
|
467
473
|
}
|
|
468
|
-
resolveStartupConfig(e,
|
|
474
|
+
resolveStartupConfig(e, t) {
|
|
469
475
|
if (e.mode) {
|
|
470
476
|
if (e.mode === "DYNAMIC" && e.toolsets)
|
|
471
477
|
return console.warn("startup.toolsets provided but ignored in DYNAMIC mode"), { mode: "DYNAMIC" };
|
|
472
478
|
if (e.mode === "STATIC") {
|
|
473
479
|
if (e.toolsets === "ALL")
|
|
474
480
|
return { mode: "STATIC", toolsets: "ALL" };
|
|
475
|
-
const
|
|
476
|
-
for (const
|
|
477
|
-
const { isValid:
|
|
478
|
-
|
|
481
|
+
const s = Array.isArray(e.toolsets) ? e.toolsets : [], o = [];
|
|
482
|
+
for (const i of s) {
|
|
483
|
+
const { isValid: a, sanitized: l, error: n } = this.toolsetValidator.validateToolsetName(i, t);
|
|
484
|
+
a && l ? o.push(l) : n && console.warn(n);
|
|
479
485
|
}
|
|
480
|
-
if (
|
|
486
|
+
if (s.length > 0 && o.length === 0)
|
|
481
487
|
throw new Error(
|
|
482
488
|
"STATIC mode requires valid toolsets or 'ALL'; none were valid"
|
|
483
489
|
);
|
|
@@ -487,16 +493,16 @@ class y {
|
|
|
487
493
|
}
|
|
488
494
|
if (e.toolsets === "ALL") return { mode: "STATIC", toolsets: "ALL" };
|
|
489
495
|
if (Array.isArray(e.toolsets) && e.toolsets.length > 0) {
|
|
490
|
-
const
|
|
496
|
+
const s = [];
|
|
491
497
|
for (const o of e.toolsets) {
|
|
492
|
-
const { isValid:
|
|
493
|
-
|
|
498
|
+
const { isValid: i, sanitized: a, error: l } = this.toolsetValidator.validateToolsetName(o, t);
|
|
499
|
+
i && a ? s.push(a) : l && console.warn(l);
|
|
494
500
|
}
|
|
495
|
-
if (
|
|
501
|
+
if (s.length === 0)
|
|
496
502
|
throw new Error(
|
|
497
503
|
"STATIC mode requires valid toolsets or 'ALL'; none were valid"
|
|
498
504
|
);
|
|
499
|
-
return { mode: "STATIC", toolsets:
|
|
505
|
+
return { mode: "STATIC", toolsets: s };
|
|
500
506
|
}
|
|
501
507
|
return { mode: "DYNAMIC" };
|
|
502
508
|
}
|
|
@@ -507,11 +513,11 @@ class y {
|
|
|
507
513
|
return this.manager;
|
|
508
514
|
}
|
|
509
515
|
}
|
|
510
|
-
class
|
|
516
|
+
class P {
|
|
511
517
|
constructor(e = {}) {
|
|
512
518
|
this.storage = /* @__PURE__ */ new Map(), this.maxSize = e.maxSize ?? 1e3, this.ttlMs = e.ttlMs ?? 1e3 * 60 * 60;
|
|
513
|
-
const
|
|
514
|
-
this.pruneInterval = setInterval(() => this.pruneExpired(),
|
|
519
|
+
const t = e.pruneIntervalMs ?? 1e3 * 60 * 10;
|
|
520
|
+
this.pruneInterval = setInterval(() => this.pruneExpired(), t);
|
|
515
521
|
}
|
|
516
522
|
getEntryCount() {
|
|
517
523
|
return this.storage.size;
|
|
@@ -523,13 +529,13 @@ class M {
|
|
|
523
529
|
return this.ttlMs;
|
|
524
530
|
}
|
|
525
531
|
get(e) {
|
|
526
|
-
const
|
|
527
|
-
return
|
|
532
|
+
const t = this.storage.get(e);
|
|
533
|
+
return t ? Date.now() - t.lastAccessed > this.ttlMs ? (this.delete(e), null) : (t.lastAccessed = Date.now(), this.storage.delete(e), this.storage.set(e, t), t.resource) : null;
|
|
528
534
|
}
|
|
529
|
-
set(e,
|
|
535
|
+
set(e, t) {
|
|
530
536
|
this.storage.size >= this.maxSize && this.evictLeastRecentlyUsed();
|
|
531
|
-
const
|
|
532
|
-
this.storage.set(e,
|
|
537
|
+
const s = { resource: t, lastAccessed: Date.now() };
|
|
538
|
+
this.storage.set(e, s);
|
|
533
539
|
}
|
|
534
540
|
delete(e) {
|
|
535
541
|
this.storage.delete(e);
|
|
@@ -543,27 +549,27 @@ class M {
|
|
|
543
549
|
}
|
|
544
550
|
pruneExpired() {
|
|
545
551
|
const e = Date.now();
|
|
546
|
-
for (const [
|
|
547
|
-
e -
|
|
552
|
+
for (const [t, s] of this.storage.entries())
|
|
553
|
+
e - s.lastAccessed > this.ttlMs && this.delete(t);
|
|
548
554
|
}
|
|
549
555
|
}
|
|
550
|
-
class
|
|
551
|
-
constructor(e,
|
|
552
|
-
this.app = null, this.clientCache = new
|
|
553
|
-
host:
|
|
554
|
-
port:
|
|
555
|
-
basePath:
|
|
556
|
-
cors:
|
|
557
|
-
logger:
|
|
558
|
-
app:
|
|
556
|
+
class J {
|
|
557
|
+
constructor(e, t, s = {}, o) {
|
|
558
|
+
this.app = null, this.clientCache = new P(), this.defaultManager = e, this.createBundle = t, this.options = {
|
|
559
|
+
host: s.host ?? "0.0.0.0",
|
|
560
|
+
port: s.port ?? 3e3,
|
|
561
|
+
basePath: s.basePath ?? "/",
|
|
562
|
+
cors: s.cors ?? !0,
|
|
563
|
+
logger: s.logger ?? !1,
|
|
564
|
+
app: s.app
|
|
559
565
|
}, this.configSchema = o;
|
|
560
566
|
}
|
|
561
567
|
async start() {
|
|
562
568
|
if (this.app) return;
|
|
563
|
-
const e = this.options.app ??
|
|
564
|
-
this.options.cors && await e.register(
|
|
565
|
-
const
|
|
566
|
-
e.get(`${
|
|
569
|
+
const e = this.options.app ?? S({ logger: this.options.logger });
|
|
570
|
+
this.options.cors && await e.register(M, { origin: !0 });
|
|
571
|
+
const t = this.options.basePath.endsWith("/") ? this.options.basePath.slice(0, -1) : this.options.basePath;
|
|
572
|
+
e.get(`${t}/healthz`, async () => ({ ok: !0 })), e.get(`${t}/tools`, async () => this.defaultManager.getStatus()), e.get(`${t}/.well-known/mcp-config`, async (s, o) => (o.header("Content-Type", "application/schema+json; charset=utf-8"), this.configSchema ?? {
|
|
567
573
|
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
568
574
|
title: "MCP Session Configuration",
|
|
569
575
|
description: "Schema for the /mcp endpoint configuration",
|
|
@@ -573,32 +579,32 @@ class L {
|
|
|
573
579
|
"x-mcp-version": "1.0",
|
|
574
580
|
"x-query-style": "dot+bracket"
|
|
575
581
|
})), e.post(
|
|
576
|
-
`${
|
|
577
|
-
async (
|
|
578
|
-
const
|
|
579
|
-
let n = l ? this.clientCache.get(
|
|
582
|
+
`${t}/mcp`,
|
|
583
|
+
async (s, o) => {
|
|
584
|
+
const i = s.headers["mcp-client-id"]?.trim(), a = i && i.length > 0 ? i : `anon-${p()}`, l = !a.startsWith("anon-");
|
|
585
|
+
let n = l ? this.clientCache.get(a) : null;
|
|
580
586
|
if (!n) {
|
|
581
|
-
const
|
|
587
|
+
const f = this.createBundle(), g = f.sessions;
|
|
582
588
|
n = {
|
|
583
|
-
server:
|
|
584
|
-
orchestrator:
|
|
585
|
-
sessions:
|
|
586
|
-
}, l && this.clientCache.set(
|
|
589
|
+
server: f.server,
|
|
590
|
+
orchestrator: f.orchestrator,
|
|
591
|
+
sessions: g instanceof Map ? g : /* @__PURE__ */ new Map()
|
|
592
|
+
}, l && this.clientCache.set(a, n);
|
|
587
593
|
}
|
|
588
|
-
const c =
|
|
589
|
-
let
|
|
594
|
+
const c = s.headers["mcp-session-id"];
|
|
595
|
+
let h;
|
|
590
596
|
if (c && n.sessions.get(c))
|
|
591
|
-
|
|
592
|
-
else if (!c &&
|
|
593
|
-
const
|
|
594
|
-
|
|
595
|
-
sessionIdGenerator: () =>
|
|
596
|
-
onsessioninitialized: (
|
|
597
|
-
n.sessions.set(
|
|
597
|
+
h = n.sessions.get(c);
|
|
598
|
+
else if (!c && x(s.body)) {
|
|
599
|
+
const f = p();
|
|
600
|
+
h = new C({
|
|
601
|
+
sessionIdGenerator: () => f,
|
|
602
|
+
onsessioninitialized: (g) => {
|
|
603
|
+
n.sessions.set(g, h);
|
|
598
604
|
}
|
|
599
605
|
});
|
|
600
606
|
try {
|
|
601
|
-
await n.server.connect(
|
|
607
|
+
await n.server.connect(h);
|
|
602
608
|
} catch {
|
|
603
609
|
return o.code(500), {
|
|
604
610
|
jsonrpc: "2.0",
|
|
@@ -606,8 +612,8 @@ class L {
|
|
|
606
612
|
id: null
|
|
607
613
|
};
|
|
608
614
|
}
|
|
609
|
-
|
|
610
|
-
|
|
615
|
+
h.onclose = () => {
|
|
616
|
+
h?.sessionId && n.sessions.delete(h.sessionId);
|
|
611
617
|
};
|
|
612
618
|
} else
|
|
613
619
|
return o.code(400), {
|
|
@@ -615,29 +621,29 @@ class L {
|
|
|
615
621
|
error: { code: -32e3, message: "Session not found or expired" },
|
|
616
622
|
id: null
|
|
617
623
|
};
|
|
618
|
-
return await
|
|
619
|
-
|
|
624
|
+
return await h.handleRequest(
|
|
625
|
+
s.raw,
|
|
620
626
|
o.raw,
|
|
621
|
-
|
|
627
|
+
s.body
|
|
622
628
|
), o;
|
|
623
629
|
}
|
|
624
|
-
), e.get(`${
|
|
625
|
-
const
|
|
626
|
-
if (!
|
|
630
|
+
), e.get(`${t}/mcp`, async (s, o) => {
|
|
631
|
+
const i = s.headers["mcp-client-id"]?.trim(), a = i && i.length > 0 ? i : "";
|
|
632
|
+
if (!a)
|
|
627
633
|
return o.code(400), "Missing mcp-client-id";
|
|
628
|
-
const l = this.clientCache.get(
|
|
634
|
+
const l = this.clientCache.get(a);
|
|
629
635
|
if (!l)
|
|
630
636
|
return o.code(400), "Invalid or expired client";
|
|
631
|
-
const n =
|
|
637
|
+
const n = s.headers["mcp-session-id"];
|
|
632
638
|
if (!n)
|
|
633
639
|
return o.code(400), "Missing mcp-session-id";
|
|
634
640
|
const c = l.sessions.get(n);
|
|
635
|
-
return c ? (await c.handleRequest(
|
|
641
|
+
return c ? (await c.handleRequest(s.raw, o.raw), o) : (o.code(400), "Invalid or expired session ID");
|
|
636
642
|
}), e.delete(
|
|
637
|
-
`${
|
|
638
|
-
async (
|
|
639
|
-
const
|
|
640
|
-
if (!
|
|
643
|
+
`${t}/mcp`,
|
|
644
|
+
async (s, o) => {
|
|
645
|
+
const i = s.headers["mcp-client-id"]?.trim(), a = i && i.length > 0 ? i : "", l = s.headers["mcp-session-id"];
|
|
646
|
+
if (!a || !l)
|
|
641
647
|
return o.code(400), {
|
|
642
648
|
jsonrpc: "2.0",
|
|
643
649
|
error: {
|
|
@@ -646,7 +652,7 @@ class L {
|
|
|
646
652
|
},
|
|
647
653
|
id: null
|
|
648
654
|
};
|
|
649
|
-
const n = this.clientCache.get(
|
|
655
|
+
const n = this.clientCache.get(a), c = n?.sessions.get(l);
|
|
650
656
|
if (!n || !c)
|
|
651
657
|
return o.code(404), {
|
|
652
658
|
jsonrpc: "2.0",
|
|
@@ -670,13 +676,13 @@ class L {
|
|
|
670
676
|
this.app && (this.options.app || await this.app.close(), this.app = null);
|
|
671
677
|
}
|
|
672
678
|
}
|
|
673
|
-
async function
|
|
674
|
-
const e =
|
|
675
|
-
if (typeof
|
|
679
|
+
async function de(r) {
|
|
680
|
+
const e = r.startup?.mode ?? "DYNAMIC";
|
|
681
|
+
if (typeof r.createServer != "function")
|
|
676
682
|
throw new Error("createMcpServer: `createServer` (factory) is required");
|
|
677
|
-
const
|
|
683
|
+
const t = r.createServer(), s = (n) => typeof n?.server?.notification == "function", o = (n) => typeof n?.notifyToolsListChanged == "function", i = async (n) => {
|
|
678
684
|
try {
|
|
679
|
-
if (
|
|
685
|
+
if (s(n)) {
|
|
680
686
|
await n.server.notification({
|
|
681
687
|
method: "notifications/tools/list_changed"
|
|
682
688
|
});
|
|
@@ -685,37 +691,37 @@ async function O(a) {
|
|
|
685
691
|
o(n) && await n.notifyToolsListChanged();
|
|
686
692
|
} catch {
|
|
687
693
|
}
|
|
688
|
-
},
|
|
689
|
-
server:
|
|
690
|
-
catalog:
|
|
691
|
-
moduleLoaders:
|
|
692
|
-
exposurePolicy:
|
|
693
|
-
context:
|
|
694
|
-
notifyToolsListChanged: async () =>
|
|
695
|
-
startup:
|
|
696
|
-
registerMetaTools:
|
|
697
|
-
}), l = new
|
|
698
|
-
|
|
694
|
+
}, a = new y({
|
|
695
|
+
server: t,
|
|
696
|
+
catalog: r.catalog,
|
|
697
|
+
moduleLoaders: r.moduleLoaders,
|
|
698
|
+
exposurePolicy: r.exposurePolicy,
|
|
699
|
+
context: r.context,
|
|
700
|
+
notifyToolsListChanged: async () => i(t),
|
|
701
|
+
startup: r.startup,
|
|
702
|
+
registerMetaTools: r.registerMetaTools !== void 0 ? r.registerMetaTools : e === "DYNAMIC"
|
|
703
|
+
}), l = new J(
|
|
704
|
+
a.getManager(),
|
|
699
705
|
() => {
|
|
700
706
|
if (e === "STATIC")
|
|
701
|
-
return { server:
|
|
702
|
-
const n =
|
|
707
|
+
return { server: t, orchestrator: a };
|
|
708
|
+
const n = r.createServer(), c = new y({
|
|
703
709
|
server: n,
|
|
704
|
-
catalog:
|
|
705
|
-
moduleLoaders:
|
|
706
|
-
exposurePolicy:
|
|
707
|
-
context:
|
|
708
|
-
notifyToolsListChanged: async () =>
|
|
709
|
-
startup:
|
|
710
|
-
registerMetaTools:
|
|
710
|
+
catalog: r.catalog,
|
|
711
|
+
moduleLoaders: r.moduleLoaders,
|
|
712
|
+
exposurePolicy: r.exposurePolicy,
|
|
713
|
+
context: r.context,
|
|
714
|
+
notifyToolsListChanged: async () => i(n),
|
|
715
|
+
startup: r.startup,
|
|
716
|
+
registerMetaTools: r.registerMetaTools !== void 0 ? r.registerMetaTools : e === "DYNAMIC"
|
|
711
717
|
});
|
|
712
718
|
return { server: n, orchestrator: c };
|
|
713
719
|
},
|
|
714
|
-
|
|
715
|
-
|
|
720
|
+
r.http,
|
|
721
|
+
r.configSchema
|
|
716
722
|
);
|
|
717
723
|
return {
|
|
718
|
-
server:
|
|
724
|
+
server: t,
|
|
719
725
|
start: async () => {
|
|
720
726
|
await l.start();
|
|
721
727
|
},
|
|
@@ -724,7 +730,476 @@ async function O(a) {
|
|
|
724
730
|
}
|
|
725
731
|
};
|
|
726
732
|
}
|
|
733
|
+
function q(r) {
|
|
734
|
+
G(r), K(r), Q(r), X(r);
|
|
735
|
+
}
|
|
736
|
+
function G(r) {
|
|
737
|
+
if (!r || typeof r != "object")
|
|
738
|
+
throw new Error(
|
|
739
|
+
"Permission configuration is required for createPermissionBasedMcpServer"
|
|
740
|
+
);
|
|
741
|
+
}
|
|
742
|
+
function K(r) {
|
|
743
|
+
if (!r.source)
|
|
744
|
+
throw new Error('Permission source must be either "headers" or "config"');
|
|
745
|
+
if (r.source !== "headers" && r.source !== "config")
|
|
746
|
+
throw new Error(
|
|
747
|
+
`Invalid permission source: "${r.source}". Must be either "headers" or "config"`
|
|
748
|
+
);
|
|
749
|
+
}
|
|
750
|
+
function Q(r) {
|
|
751
|
+
if (r.source === "config" && !r.staticMap && !r.resolver)
|
|
752
|
+
throw new Error(
|
|
753
|
+
"Config-based permissions require at least one of: staticMap or resolver function"
|
|
754
|
+
);
|
|
755
|
+
}
|
|
756
|
+
function X(r) {
|
|
757
|
+
if (r.staticMap !== void 0) {
|
|
758
|
+
if (typeof r.staticMap != "object" || r.staticMap === null)
|
|
759
|
+
throw new Error(
|
|
760
|
+
"staticMap must be an object mapping client IDs to toolset arrays"
|
|
761
|
+
);
|
|
762
|
+
Z(r.staticMap);
|
|
763
|
+
}
|
|
764
|
+
if (r.resolver !== void 0 && typeof r.resolver != "function")
|
|
765
|
+
throw new Error(
|
|
766
|
+
"resolver must be a synchronous function: (clientId: string) => string[]"
|
|
767
|
+
);
|
|
768
|
+
if (r.defaultPermissions !== void 0 && !Array.isArray(r.defaultPermissions))
|
|
769
|
+
throw new Error("defaultPermissions must be an array of toolset names");
|
|
770
|
+
if (r.headerName !== void 0 && (typeof r.headerName != "string" || r.headerName.length === 0))
|
|
771
|
+
throw new Error("headerName must be a non-empty string");
|
|
772
|
+
}
|
|
773
|
+
function Z(r) {
|
|
774
|
+
for (const [e, t] of Object.entries(r))
|
|
775
|
+
if (!Array.isArray(t))
|
|
776
|
+
throw new Error(
|
|
777
|
+
`staticMap value for client "${e}" must be an array of toolset names`
|
|
778
|
+
);
|
|
779
|
+
}
|
|
780
|
+
var m, $, E, L, N;
|
|
781
|
+
class ee {
|
|
782
|
+
/**
|
|
783
|
+
* Creates a new PermissionResolver instance.
|
|
784
|
+
* @param config - The permission configuration defining how permissions are resolved
|
|
785
|
+
*/
|
|
786
|
+
constructor(e) {
|
|
787
|
+
v(this, m);
|
|
788
|
+
this.config = e, this.cache = /* @__PURE__ */ new Map();
|
|
789
|
+
}
|
|
790
|
+
/**
|
|
791
|
+
* Resolves permissions for a client based on the configured source.
|
|
792
|
+
* Results are cached to improve performance for subsequent requests from the same client.
|
|
793
|
+
* Handles all errors gracefully by returning empty permissions on failure.
|
|
794
|
+
* @param clientId - The unique identifier for the client
|
|
795
|
+
* @param headers - Optional request headers (required for header-based permissions)
|
|
796
|
+
* @returns Array of toolset names the client is allowed to access
|
|
797
|
+
*/
|
|
798
|
+
resolvePermissions(e, t) {
|
|
799
|
+
if (this.cache.has(e))
|
|
800
|
+
return this.cache.get(e);
|
|
801
|
+
let s;
|
|
802
|
+
try {
|
|
803
|
+
this.config.source === "headers" ? s = u(this, m, $).call(this, t) : s = u(this, m, E).call(this, e), Array.isArray(s) || (console.warn(
|
|
804
|
+
`Permission resolution returned non-array for client ${e}, using empty permissions`
|
|
805
|
+
), s = []), s = s.filter(
|
|
806
|
+
(o) => typeof o == "string" && o.trim().length > 0
|
|
807
|
+
);
|
|
808
|
+
} catch (o) {
|
|
809
|
+
console.error(
|
|
810
|
+
`Unexpected error resolving permissions for client ${e}:`,
|
|
811
|
+
o
|
|
812
|
+
), s = [];
|
|
813
|
+
}
|
|
814
|
+
return this.cache.set(e, s), s;
|
|
815
|
+
}
|
|
816
|
+
/**
|
|
817
|
+
* Clears the permission cache.
|
|
818
|
+
* Useful for cleanup during server shutdown or when permissions need to be refreshed.
|
|
819
|
+
*/
|
|
820
|
+
clearCache() {
|
|
821
|
+
this.cache.clear();
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
m = new WeakSet(), /**
|
|
825
|
+
* Parses permissions from request headers.
|
|
826
|
+
* Extracts comma-separated toolset names from the configured header.
|
|
827
|
+
* Handles malformed headers gracefully by returning empty permissions.
|
|
828
|
+
* @param headers - Request headers containing permission data
|
|
829
|
+
* @returns Array of toolset names from headers, or empty array if header is missing/malformed
|
|
830
|
+
* @private
|
|
831
|
+
*/
|
|
832
|
+
$ = function(e) {
|
|
833
|
+
const t = this.config.headerName || "mcp-toolset-permissions", s = e?.[t];
|
|
834
|
+
if (!s)
|
|
835
|
+
return [];
|
|
836
|
+
try {
|
|
837
|
+
return s.split(",").map((o) => o.trim()).filter((o) => o.length > 0);
|
|
838
|
+
} catch (o) {
|
|
839
|
+
return console.warn(
|
|
840
|
+
`Failed to parse permission header '${t}':`,
|
|
841
|
+
o
|
|
842
|
+
), [];
|
|
843
|
+
}
|
|
844
|
+
}, /**
|
|
845
|
+
* Resolves permissions from server-side configuration.
|
|
846
|
+
* Tries resolver function first (if provided), then falls back to static map,
|
|
847
|
+
* and finally to default permissions. Handles errors gracefully.
|
|
848
|
+
* @param clientId - The unique identifier for the client
|
|
849
|
+
* @returns Array of toolset names from configuration
|
|
850
|
+
* @private
|
|
851
|
+
*/
|
|
852
|
+
E = function(e) {
|
|
853
|
+
if (this.config.resolver) {
|
|
854
|
+
const t = u(this, m, L).call(this, e);
|
|
855
|
+
if (t !== null)
|
|
856
|
+
return t;
|
|
857
|
+
}
|
|
858
|
+
if (this.config.staticMap) {
|
|
859
|
+
const t = u(this, m, N).call(this, e);
|
|
860
|
+
if (t !== null)
|
|
861
|
+
return t;
|
|
862
|
+
}
|
|
863
|
+
return this.config.defaultPermissions || [];
|
|
864
|
+
}, /**
|
|
865
|
+
* Attempts to resolve permissions using the configured resolver function.
|
|
866
|
+
* Handles errors gracefully and returns null on failure to allow fallback.
|
|
867
|
+
* @param clientId - The unique identifier for the client
|
|
868
|
+
* @returns Array of toolset names if successful, null if resolver fails or returns invalid data
|
|
869
|
+
* @private
|
|
870
|
+
*/
|
|
871
|
+
L = function(e) {
|
|
872
|
+
try {
|
|
873
|
+
const t = this.config.resolver(e);
|
|
874
|
+
return Array.isArray(t) ? t : (console.warn(
|
|
875
|
+
`Permission resolver returned non-array for client ${e}, using fallback`
|
|
876
|
+
), null);
|
|
877
|
+
} catch (t) {
|
|
878
|
+
const s = t instanceof Error ? t.message : String(t);
|
|
879
|
+
return console.warn(
|
|
880
|
+
`Permission resolver declined client ${e} (${s}), trying fallback`
|
|
881
|
+
), null;
|
|
882
|
+
}
|
|
883
|
+
}, /**
|
|
884
|
+
* Looks up permissions in the static map configuration.
|
|
885
|
+
* Returns null if client is not found to allow fallback to defaults.
|
|
886
|
+
* @param clientId - The unique identifier for the client
|
|
887
|
+
* @returns Array of toolset names if found, null if client not in map
|
|
888
|
+
* @private
|
|
889
|
+
*/
|
|
890
|
+
N = function(e) {
|
|
891
|
+
const t = this.config.staticMap[e];
|
|
892
|
+
return t !== void 0 ? Array.isArray(t) ? t : [] : null;
|
|
893
|
+
};
|
|
894
|
+
function se(r, e) {
|
|
895
|
+
return async (t) => {
|
|
896
|
+
const s = e.resolvePermissions(
|
|
897
|
+
t.clientId,
|
|
898
|
+
t.headers
|
|
899
|
+
), o = r(s), i = o.orchestrator.getManager();
|
|
900
|
+
return s.length > 0 && await i.enableToolsets(s), {
|
|
901
|
+
server: o.server,
|
|
902
|
+
orchestrator: o.orchestrator,
|
|
903
|
+
allowedToolsets: s
|
|
904
|
+
};
|
|
905
|
+
};
|
|
906
|
+
}
|
|
907
|
+
var d, D, j, z, O, R, k, F, V, _;
|
|
908
|
+
class te {
|
|
909
|
+
/**
|
|
910
|
+
* Creates a new PermissionAwareFastifyTransport instance.
|
|
911
|
+
* @param defaultManager - Default tool manager for status endpoints
|
|
912
|
+
* @param createPermissionAwareBundle - Function to create permission-aware bundles
|
|
913
|
+
* @param options - Transport configuration options
|
|
914
|
+
* @param configSchema - Optional JSON schema for configuration discovery
|
|
915
|
+
*/
|
|
916
|
+
constructor(e, t, s = {}, o) {
|
|
917
|
+
v(this, d);
|
|
918
|
+
this.app = null, this.clientCache = new P(), this.defaultManager = e, this.createPermissionAwareBundle = t, this.options = {
|
|
919
|
+
host: s.host ?? "0.0.0.0",
|
|
920
|
+
port: s.port ?? 3e3,
|
|
921
|
+
basePath: s.basePath ?? "/",
|
|
922
|
+
cors: s.cors ?? !0,
|
|
923
|
+
logger: s.logger ?? !1,
|
|
924
|
+
app: s.app
|
|
925
|
+
}, this.configSchema = o;
|
|
926
|
+
}
|
|
927
|
+
/**
|
|
928
|
+
* Starts the Fastify server and registers all MCP endpoints.
|
|
929
|
+
* Sets up routes for health checks, tool status, and MCP protocol handling.
|
|
930
|
+
*/
|
|
931
|
+
async start() {
|
|
932
|
+
if (this.app) return;
|
|
933
|
+
const e = this.options.app ?? S({ logger: this.options.logger });
|
|
934
|
+
this.options.cors && await e.register(M, { origin: !0 });
|
|
935
|
+
const t = u(this, d, D).call(this, this.options.basePath);
|
|
936
|
+
u(this, d, j).call(this, e, t), u(this, d, z).call(this, e, t), u(this, d, O).call(this, e, t), u(this, d, R).call(this, e, t), u(this, d, k).call(this, e, t), u(this, d, F).call(this, e, t), this.options.app || await e.listen({ host: this.options.host, port: this.options.port }), this.app = e;
|
|
937
|
+
}
|
|
938
|
+
/**
|
|
939
|
+
* Stops the Fastify server and cleans up resources.
|
|
940
|
+
*/
|
|
941
|
+
async stop() {
|
|
942
|
+
this.app && (this.options.app || await this.app.close(), this.app = null);
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
d = new WeakSet(), /**
|
|
946
|
+
* Normalizes the base path by removing trailing slashes.
|
|
947
|
+
* @param basePath - The base path to normalize
|
|
948
|
+
* @returns Normalized base path without trailing slash
|
|
949
|
+
* @private
|
|
950
|
+
*/
|
|
951
|
+
D = function(e) {
|
|
952
|
+
return e.endsWith("/") ? e.slice(0, -1) : e;
|
|
953
|
+
}, /**
|
|
954
|
+
* Registers the health check endpoint.
|
|
955
|
+
* @param app - Fastify instance
|
|
956
|
+
* @param base - Base path for routes
|
|
957
|
+
* @private
|
|
958
|
+
*/
|
|
959
|
+
j = function(e, t) {
|
|
960
|
+
e.get(`${t}/healthz`, async () => ({ ok: !0 }));
|
|
961
|
+
}, /**
|
|
962
|
+
* Registers the tools status endpoint.
|
|
963
|
+
* @param app - Fastify instance
|
|
964
|
+
* @param base - Base path for routes
|
|
965
|
+
* @private
|
|
966
|
+
*/
|
|
967
|
+
z = function(e, t) {
|
|
968
|
+
e.get(`${t}/tools`, async () => this.defaultManager.getStatus());
|
|
969
|
+
}, /**
|
|
970
|
+
* Registers the MCP configuration discovery endpoint.
|
|
971
|
+
* @param app - Fastify instance
|
|
972
|
+
* @param base - Base path for routes
|
|
973
|
+
* @private
|
|
974
|
+
*/
|
|
975
|
+
O = function(e, t) {
|
|
976
|
+
e.get(`${t}/.well-known/mcp-config`, async (s, o) => (o.header("Content-Type", "application/schema+json; charset=utf-8"), this.configSchema ?? {
|
|
977
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
978
|
+
title: "MCP Session Configuration",
|
|
979
|
+
description: "Schema for the /mcp endpoint configuration",
|
|
980
|
+
type: "object",
|
|
981
|
+
properties: {},
|
|
982
|
+
required: [],
|
|
983
|
+
"x-mcp-version": "1.0",
|
|
984
|
+
"x-query-style": "dot+bracket"
|
|
985
|
+
}));
|
|
986
|
+
}, /**
|
|
987
|
+
* Registers the POST /mcp endpoint for JSON-RPC requests.
|
|
988
|
+
* Extracts client context, resolves permissions, and handles MCP protocol.
|
|
989
|
+
* @param app - Fastify instance
|
|
990
|
+
* @param base - Base path for routes
|
|
991
|
+
* @private
|
|
992
|
+
*/
|
|
993
|
+
R = function(e, t) {
|
|
994
|
+
e.post(
|
|
995
|
+
`${t}/mcp`,
|
|
996
|
+
async (s, o) => {
|
|
997
|
+
const i = u(this, d, V).call(this, s), a = !i.clientId.startsWith("anon-");
|
|
998
|
+
let l = a ? this.clientCache.get(i.clientId) : null;
|
|
999
|
+
if (!l)
|
|
1000
|
+
try {
|
|
1001
|
+
const h = await this.createPermissionAwareBundle(i), f = h.sessions;
|
|
1002
|
+
l = {
|
|
1003
|
+
server: h.server,
|
|
1004
|
+
orchestrator: h.orchestrator,
|
|
1005
|
+
allowedToolsets: h.allowedToolsets,
|
|
1006
|
+
sessions: f instanceof Map ? f : /* @__PURE__ */ new Map()
|
|
1007
|
+
}, a && this.clientCache.set(i.clientId, l);
|
|
1008
|
+
} catch (h) {
|
|
1009
|
+
return console.error(
|
|
1010
|
+
`Failed to create permission-aware bundle for client ${i.clientId}:`,
|
|
1011
|
+
h
|
|
1012
|
+
), o.code(403), u(this, d, _).call(this, "Access denied");
|
|
1013
|
+
}
|
|
1014
|
+
const n = s.headers["mcp-session-id"];
|
|
1015
|
+
let c;
|
|
1016
|
+
if (n && l.sessions.get(n))
|
|
1017
|
+
c = l.sessions.get(n);
|
|
1018
|
+
else if (!n && x(s.body)) {
|
|
1019
|
+
const h = p();
|
|
1020
|
+
c = new C({
|
|
1021
|
+
sessionIdGenerator: () => h,
|
|
1022
|
+
onsessioninitialized: (f) => {
|
|
1023
|
+
l.sessions.set(f, c);
|
|
1024
|
+
}
|
|
1025
|
+
});
|
|
1026
|
+
try {
|
|
1027
|
+
await l.server.connect(c);
|
|
1028
|
+
} catch {
|
|
1029
|
+
return o.code(500), {
|
|
1030
|
+
jsonrpc: "2.0",
|
|
1031
|
+
error: { code: -32603, message: "Error initializing server." },
|
|
1032
|
+
id: null
|
|
1033
|
+
};
|
|
1034
|
+
}
|
|
1035
|
+
c.onclose = () => {
|
|
1036
|
+
c?.sessionId && l.sessions.delete(c.sessionId);
|
|
1037
|
+
};
|
|
1038
|
+
} else
|
|
1039
|
+
return o.code(400), {
|
|
1040
|
+
jsonrpc: "2.0",
|
|
1041
|
+
error: { code: -32e3, message: "Session not found or expired" },
|
|
1042
|
+
id: null
|
|
1043
|
+
};
|
|
1044
|
+
return await c.handleRequest(
|
|
1045
|
+
s.raw,
|
|
1046
|
+
o.raw,
|
|
1047
|
+
s.body
|
|
1048
|
+
), o;
|
|
1049
|
+
}
|
|
1050
|
+
);
|
|
1051
|
+
}, /**
|
|
1052
|
+
* Registers the GET /mcp endpoint for SSE notifications.
|
|
1053
|
+
* @param app - Fastify instance
|
|
1054
|
+
* @param base - Base path for routes
|
|
1055
|
+
* @private
|
|
1056
|
+
*/
|
|
1057
|
+
k = function(e, t) {
|
|
1058
|
+
e.get(`${t}/mcp`, async (s, o) => {
|
|
1059
|
+
const i = s.headers["mcp-client-id"]?.trim(), a = i && i.length > 0 ? i : "";
|
|
1060
|
+
if (!a)
|
|
1061
|
+
return o.code(400), "Missing mcp-client-id";
|
|
1062
|
+
const l = this.clientCache.get(a);
|
|
1063
|
+
if (!l)
|
|
1064
|
+
return o.code(400), "Invalid or expired client";
|
|
1065
|
+
const n = s.headers["mcp-session-id"];
|
|
1066
|
+
if (!n)
|
|
1067
|
+
return o.code(400), "Missing mcp-session-id";
|
|
1068
|
+
const c = l.sessions.get(n);
|
|
1069
|
+
return c ? (await c.handleRequest(s.raw, o.raw), o) : (o.code(400), "Invalid or expired session ID");
|
|
1070
|
+
});
|
|
1071
|
+
}, /**
|
|
1072
|
+
* Registers the DELETE /mcp endpoint for session termination.
|
|
1073
|
+
* @param app - Fastify instance
|
|
1074
|
+
* @param base - Base path for routes
|
|
1075
|
+
* @private
|
|
1076
|
+
*/
|
|
1077
|
+
F = function(e, t) {
|
|
1078
|
+
e.delete(
|
|
1079
|
+
`${t}/mcp`,
|
|
1080
|
+
async (s, o) => {
|
|
1081
|
+
const i = s.headers["mcp-client-id"]?.trim(), a = i && i.length > 0 ? i : "", l = s.headers["mcp-session-id"];
|
|
1082
|
+
if (!a || !l)
|
|
1083
|
+
return o.code(400), {
|
|
1084
|
+
jsonrpc: "2.0",
|
|
1085
|
+
error: {
|
|
1086
|
+
code: -32600,
|
|
1087
|
+
message: "Missing mcp-client-id or mcp-session-id header"
|
|
1088
|
+
},
|
|
1089
|
+
id: null
|
|
1090
|
+
};
|
|
1091
|
+
const n = this.clientCache.get(a), c = n?.sessions.get(l);
|
|
1092
|
+
if (!n || !c)
|
|
1093
|
+
return o.code(404), {
|
|
1094
|
+
jsonrpc: "2.0",
|
|
1095
|
+
error: { code: -32e3, message: "Session not found or expired" },
|
|
1096
|
+
id: null
|
|
1097
|
+
};
|
|
1098
|
+
try {
|
|
1099
|
+
if (typeof c.close == "function")
|
|
1100
|
+
try {
|
|
1101
|
+
await c.close();
|
|
1102
|
+
} catch {
|
|
1103
|
+
}
|
|
1104
|
+
} finally {
|
|
1105
|
+
c?.sessionId ? n.sessions.delete(c.sessionId) : n.sessions.delete(l);
|
|
1106
|
+
}
|
|
1107
|
+
return o.code(204).send(), o;
|
|
1108
|
+
}
|
|
1109
|
+
);
|
|
1110
|
+
}, /**
|
|
1111
|
+
* Extracts client context from the request.
|
|
1112
|
+
* Generates anonymous client ID if not provided in headers.
|
|
1113
|
+
* @param req - Fastify request object
|
|
1114
|
+
* @returns Client request context with ID and headers
|
|
1115
|
+
* @private
|
|
1116
|
+
*/
|
|
1117
|
+
V = function(e) {
|
|
1118
|
+
const t = e.headers["mcp-client-id"]?.trim(), s = t && t.length > 0 ? t : `anon-${p()}`, o = {};
|
|
1119
|
+
for (const [i, a] of Object.entries(e.headers))
|
|
1120
|
+
typeof a == "string" && (o[i] = a);
|
|
1121
|
+
return { clientId: s, headers: o };
|
|
1122
|
+
}, /**
|
|
1123
|
+
* Creates a safe error response that doesn't expose unauthorized toolset information.
|
|
1124
|
+
* Used for permission-related errors to prevent information leakage.
|
|
1125
|
+
* @param message - Generic error message to return to client
|
|
1126
|
+
* @param code - JSON-RPC error code (default: -32000 for server error)
|
|
1127
|
+
* @returns JSON-RPC error response object
|
|
1128
|
+
* @private
|
|
1129
|
+
*/
|
|
1130
|
+
_ = function(e = "Access denied", t = -32e3) {
|
|
1131
|
+
return {
|
|
1132
|
+
jsonrpc: "2.0",
|
|
1133
|
+
error: {
|
|
1134
|
+
code: t,
|
|
1135
|
+
message: e
|
|
1136
|
+
},
|
|
1137
|
+
id: null
|
|
1138
|
+
};
|
|
1139
|
+
};
|
|
1140
|
+
async function he(r) {
|
|
1141
|
+
if (!r.permissions)
|
|
1142
|
+
throw new Error(
|
|
1143
|
+
"Permission configuration is required for createPermissionBasedMcpServer. Please provide a 'permissions' field in the options."
|
|
1144
|
+
);
|
|
1145
|
+
if (q(r.permissions), r.startup)
|
|
1146
|
+
throw new Error(
|
|
1147
|
+
"Permission-based servers determine toolsets from client permissions. The 'startup' option is not allowed. Remove it from your configuration."
|
|
1148
|
+
);
|
|
1149
|
+
if (typeof r.createServer != "function")
|
|
1150
|
+
throw new Error(
|
|
1151
|
+
"createPermissionBasedMcpServer: `createServer` (factory) is required"
|
|
1152
|
+
);
|
|
1153
|
+
const e = new ee(r.permissions), t = r.createServer(), s = new y({
|
|
1154
|
+
server: t,
|
|
1155
|
+
catalog: r.catalog,
|
|
1156
|
+
moduleLoaders: r.moduleLoaders,
|
|
1157
|
+
exposurePolicy: r.exposurePolicy,
|
|
1158
|
+
context: r.context,
|
|
1159
|
+
notifyToolsListChanged: void 0,
|
|
1160
|
+
// No notifications in STATIC mode
|
|
1161
|
+
startup: { mode: "STATIC", toolsets: [] },
|
|
1162
|
+
registerMetaTools: !1
|
|
1163
|
+
}), o = se(
|
|
1164
|
+
(a) => {
|
|
1165
|
+
const l = r.createServer(), n = new y({
|
|
1166
|
+
server: l,
|
|
1167
|
+
catalog: r.catalog,
|
|
1168
|
+
moduleLoaders: r.moduleLoaders,
|
|
1169
|
+
exposurePolicy: r.exposurePolicy,
|
|
1170
|
+
context: r.context,
|
|
1171
|
+
notifyToolsListChanged: void 0,
|
|
1172
|
+
// No notifications in STATIC mode
|
|
1173
|
+
startup: { mode: "STATIC", toolsets: [] },
|
|
1174
|
+
// Empty - we'll enable manually
|
|
1175
|
+
registerMetaTools: !1
|
|
1176
|
+
// No meta-tools - toolsets are fixed per client
|
|
1177
|
+
});
|
|
1178
|
+
return { server: l, orchestrator: n };
|
|
1179
|
+
},
|
|
1180
|
+
e
|
|
1181
|
+
), i = new te(
|
|
1182
|
+
s.getManager(),
|
|
1183
|
+
o,
|
|
1184
|
+
r.http,
|
|
1185
|
+
r.configSchema
|
|
1186
|
+
);
|
|
1187
|
+
return {
|
|
1188
|
+
server: t,
|
|
1189
|
+
start: async () => {
|
|
1190
|
+
await i.start();
|
|
1191
|
+
},
|
|
1192
|
+
close: async () => {
|
|
1193
|
+
try {
|
|
1194
|
+
await i.stop();
|
|
1195
|
+
} finally {
|
|
1196
|
+
e.clearCache();
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
};
|
|
1200
|
+
}
|
|
727
1201
|
export {
|
|
728
|
-
|
|
1202
|
+
de as createMcpServer,
|
|
1203
|
+
he as createPermissionBasedMcpServer
|
|
729
1204
|
};
|
|
730
1205
|
//# sourceMappingURL=index.js.map
|